Lesson 8.2
Classes and Objects
Let us continue with the Student
class. For now, don't bother too much about the variable self
. We will get to that soon.
As we saw at the end of the previous lesson, an object of the class Student
can be created like this:
Notice that we have used the name of the class in the RHS of the assignment statement. This invokes what is called the constructor — __init__()
method — of the class. Since the constructor has two parameters (ignore self
for now) name
and marks
, we have to pass them as arguments while creating the object.
The two arguments are then assigned to self.name
and self.marks
respectively. These two variables are called the attributes of the object. Attributes can be accessed using the .
operator:
__init__()
, update_marks()
and print_details()
are called methods. A method is effectively just a function that is defined in a class. Methods can be accessed using an object. If we wish to update Anish's marks to \(95\), then we invoke the method using the object anish
:
When anish.update_marks(95)
is called, the attribute marks
that is tied to the object anish
is updated to \(95\).
To summarize, anish
is an object of type Student
having two attributes — name
and marks
— that can be accessed using the .
operator. This object is also equipped with two methods (ignoring the constructor), one to update the marks and the other to print the details of the object. Attributes define the state of an object. Different objects of the same class could have different attributes. Naively speaking, methods help to update the values of the attributes. Therefore, the methods capture the behaviour of the object.
self
Some of you might be wondering about the variable self
that crops in so many places in the definition of the class. The variable self
is used to point to the current object. To get a better understanding, let us create two different Student
objects:
How do we print the details of the student Lakshmi?
When this method is called, Python actually ends up invoking the following function:
That is, it passes the current object as an argument. So, the variable self
points to the current object. Another example:
This is equivalent to the function call:
This is a mechanism that Python uses to know the object that it is dealing with. And for this reason, the first parameter in every method defined in a class will be self
, and it will point to the object calling the method i.e., the current object.
This should also clear up any confusion that lines 3 and 4 could have caused:
self.name = name
is the following operation: assign the value of the argument name
to the current object's attribute self.name
. A similar operation follows for self.marks
.
Class Attributes vs Object Attributes
So far all attributes that we have seen are object attributes. Given an attribute, say name
or marks
, it is different for different objects. The name
attribute of anish
is different from the corresponding attribute fo the object lakshmi
. Now, we shall see another kind of attribute.
Let us say that we wish to keep track of the number students in our program. That is, when a new student joins our program, we need to update a counter. How do we do that? We need an attribute that is common to all objects and is not tied to any individual object. At the same time, we should be able to update this attribute whenever a new object is created. This is where the concept of class attributes comes in:
Now, let us say that three students join the program:
This gives the following output:
Notice that we have used Student.counter
to access the attribute counter
. Such attributes are called class attributes. All objects of the class share this attribute. At this stage, we can try the following exercise. What do you think the output will be?
OUTPUT
A class attribute can be accessed by any of the objects. But, now, try to run this code:
This seems confusing! But a moment's thought will convince you that it is not so hard. In line 20, we are creating an object attribute with the same name as the class attribute! If the same attribute name occurs in both an object and a class, then Python prioritizes the object attribute. In other words, when we change madhavan.counter
, Student.counter
remains unchanged because madhavan.counter
gets delinked from Student.counter
and becomes a new object attribute specific to madhavan
. To change Student.counter
:
OUTPUT
Now try this as an exercise and try to figure out why the output is the way it is:
OUTPUT
This demonstrates an important fact: class attributes cannot be updated by an object! At best, they can be referenced or accessed using an object
This also introduces another important point: object attributes can be created dynamically during runtime. So far, we have seen object attributes being created within the constructor. This is not binding. For example, consider the following snippet:
class Student:
def __init__(self, name):
self.name = name
anish = Student('Anish')
anish.maths = 100
anish.physics = 90
anish.chem = 70
We have created three more object attributes on the fly. It is interesting to note the subtle difference between the attribute name
and the three new attributes maths
, physics
and chem
. Any object of Student
will have the attribute name
when it is initially created, of course with a different value for name
depending on the object. But the attributes maths
, physics
and chem
are unique to the object anish
.