Python Instance Methods And Attributes

Python Instance Methods And Attributes

In the last tutorial, we learned how to define a basic Python class and create an instance of it. In this tutorial, we are going to see how to create instance methods and attributes for our class. Instance methods require an object of its class to be created before it can be called. An instance method always takes the self keyword as the first argument. It points to the instance, or object, of the class it was created from. The self parameter makes it possible for instance methods to access attributes or other methods of the same object. Instance attributes hold values that are unique to each instance of an object created from a class. They are variables belonging to only one object and are only accessible in the scope of the object. Let’s see how instance methods and attributes work with some code.


Init Instance Attributes

The __init__ function is called when the instance is created and ready to be initialized. It is an instance method that sets things up in the object. In the code above, we have some properties of the object, also known as instance attributes. A Monitor may have a model, resolution, screensize, and price. We represent these things using instance attributes.


Define An Instance Method

Highlighted above is an example of adding a second instance method to a Python class. It is quite similar to defining a normal function, as the same def keyword is used. Like with all instance methods, the first parameter to the function is self. You may use a variable that is named differently for self, but it is discouraged since self is the accepted convention in Python.


Create Object Instances

Now are are able to create a few object instances from the class. Here we create three distinct objects, each representing a monitor. During the creation of each object, we pass in the needed arguments so that each object is initialized with the correct values for its instance attributes.


Calling An Instance Method

This monitor has a price of 109.99

Each object has access to the instance method we defined, as well as to all of the instance attributes. Here we call the .getPrice() instance method on the second object that was created, monitor2. It correctly reaches into the object to find it’s price, and lets us know that This monitor has a price of 109.99.


Instance Attributes Outside Of Init

Instance attributes are not specific only to the __init__ function, they can be defined elsewhere in the object as well. That is exactly what we do above when we set a discount on the monitor. We added a new instance method named setDiscount(). That method has self as the first parameter, but also a second amount parameter. When the setDiscount() method is called, the value passed in for amount gets assigned to the instance attribute of _discount. That leading underscore is there to imply that this attribute is internal to the class and should not be accessed from outside the class’s logic. In other object-oriented languages, this is where you would use the private keyword, but Python does not have that feature.


Python hasattr()

When instance attributes are defined in the __init__ method, then the programmer can count on those attribute values being available when an object is created and put to use. This is not the case for instance attributes that are outside of the __init__ method. In our example, a Monitor object will only have a _discount instance attribute if the setDiscount() method is called *after* the object has been created. Otherwise, that instance attribute does not exist. To account for this scenario, Python has the built in hasattr() function.

Our monitor object may or may not have a _discount instance attribute. In the code above, we use the hasattr() function to determine if the _discount instance attribute is preset, and if it is, we change the behavior in the getPrice() method. This is a good example of why you might need to use the hasattr() function.


Double Underscore Instance Attributes

When we used the single leading underscore for the _discount attribute, it gave us a hint that this attribute is meant to be hidden. Python does not actually enforce this at all. There is another option that is more strict, and that is by using a double leading underscore for an instance attribute. If you use a double underscore as the start of an attribute or method name, then the python interpreter will change the name of that attribute or method so that other classes will get an error if they try to access it.

Traceback (most recent call last):
  File "C:/python/justhacking/lists.py", line 20, in 
    print(monitor1.__revision)
AttributeError: 'Monitor' object has no attribute '__revision'

Running the code above produces an attribute error as we see. The reason this happened is that because we used a double underscore, Python dynamically changed the name of the attribute by prefixing the name of the attribute with the class name in a process known as name mangling. This is used to prevent subclasses from inadvertently overriding the attribute. In reality, if you simply call the code like so:

A

then the code runs. It’s not a perfect solution, but it does provide some degree of data hiding when it is needed. You can use this approach to make sure that subclasses don’t use the same name for an attribute that you’ve already used if that is what is needed. In some cases, you will want to be able to override the attribute.