self keyword
Understanding self in Python with Examples
When we create several objects from a class, each object can hold different data. A method needs a way to access the data of the object on which it is called.
In an instance method, self refers to the object receiving the method call.
Although people sometimes call it the “self keyword,” self is not a Python keyword. It is the standard name used for the first parameter of an instance method.
Let us understand it through a few examples.
Accessing the Current Object
Consider this simple class:
class Student:
def display(self):
print("Name:", self.name)
student1 = Student()
student1.name = "Rahul"
student1.display()
Output:
Name: Rahul
When we call:
student1.display()
Python automatically passes the object referenced by student1 to the method’s first parameter, self.
Inside this call:
self.name
accesses the same attribute as:
student1.name
We write self.name inside the method so that the method can work with any Student object.
Using the Same Method with Different Objects
Let us create two students:
class Student:
def display(self):
print("Name:", self.name)
student1 = Student()
student1.name = "Rahul"
student2 = Student()
student2.name = "Anjali"
student1.display()
student2.display()
Output:
Name: Rahul Name: Anjali
The method is defined only once, but it displays different names.
| Method call | self refers to | self.name |
|---|---|---|
| student1.display() | The first student object | "Rahul" |
| student2.display() | The second student object | "Anjali" |
self does not permanently refer to one particular object. Its value depends on the object used in that call.
Seeing How the Object Is Passed
For the method above, these two calls are equivalent:
student1.display() Student.display(student1)
Output:
Name: Rahul Name: Rahul
In the first call, Python supplies the object automatically. In the second, we explicitly supply it through the class.
This explains why the definition contains a parameter even though the usual call has no arguments inside the parentheses:
def display(self):
print("Name:", self.name)
student1.display()
The object before the dot supplies self.
Using self inside __init__()
We can initialize student details when creating the object:
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
student1 = Student("Rahul", 85)
student2 = Student("Anjali", 92)
print(student1.name, student1.marks)
print(student2.name, student2.marks)
Output:
Rahul 85 Anjali 92
During initialization, self refers to the newly created instance.
Look closely at this assignment:
self.name = name
| Expression | Meaning |
|---|---|
| name | A local parameter receiving the supplied name |
| self.name | An attribute belonging to the object |
For the first student, the assignment stores "Rahul" in that object’s name attribute.
The parameter and attribute do not need matching names. This also works:
class Student:
def __init__(self, student_name, student_marks):
self.name = student_name
self.marks = student_marks
Using matching names is simply a common, readable convention.
Updating the Object’s Data
A method can use self to change the object’s attributes.
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def add_marks(self, extra_marks):
self.marks += extra_marks
student1 = Student("Rahul", 80)
student2 = Student("Anjali", 90)
student1.add_marks(5)
print(student1.name, student1.marks)
print(student2.name, student2.marks)
Output:
Rahul 85 Anjali 90
In this call:
student1.add_marks(5)
the parameters receive:
| Parameter | Value |
|---|---|
| self | The object referenced by student1 |
| extra_marks | 5 |
Only Rahul’s marks change because self.marks accesses the first student’s attribute during this call.
Calling Another Method through self
An instance method can call another method on the same object.
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def get_result(self):
if self.marks >= 40:
return "Pass"
return "Fail"
def display(self):
print("Name:", self.name)
print("Marks:", self.marks)
print("Result:", self.get_result())
student1 = Student("Rahul", 85)
student2 = Student("Anjali", 35)
student1.display()
print()
student2.display()
Output:
Name: Rahul Marks: 85 Result: Pass Name: Anjali Marks: 35 Result: Fail
Inside display():
self.get_result()
calls get_result() on the same student object.
When student1.display() runs, it calculates Rahul’s result. When student2.display() runs, it calculates Anjali’s result.
Forgetting self in the Method Definition
Consider this incorrect definition:
class Student:
def display():
print("Student details")
student1 = Student()
student1.display()
Error:
TypeError: Student.display() takes 0 positional arguments but 1 was given
Although we wrote no arguments inside the parentheses, Python automatically passed the student object. The method definition has no parameter to receive it.
Correct the definition by adding self:
class Student:
def display(self):
print("Student details")
An ordinary instance method needs this first parameter even if its body does not use the object.
Creating a Local Variable Instead of Updating an Attribute
Here is another mistake:
class Student:
def __init__(self, marks):
self.marks = marks
def update_marks(self, new_marks):
marks = new_marks
student1 = Student(70)
student1.update_marks(95)
print(student1.marks)
Output:
70
The statement:
marks = new_marks
creates a local variable. It does not change the object’s attribute.
Use:
def update_marks(self, new_marks):
self.marks = new_marks
Now calling student1.update_marks(95) changes the object’s marks to 95.
Can We Use a Different Name?
Because self is not a keyword, another parameter name is technically allowed:
class Student:
def __init__(current, name):
current.name = name
def display(current):
print(current.name)
student1 = Student("Rahul")
student1.display()
Output:
Rahul
Python passes the instance to the first parameter, regardless of that parameter’s name.
However, use self in your programs. It is the convention Python programmers expect.
Practice: A Counter Object
Create a Counter class with:
-
An instance attribute named count, initialized to 0.
-
An increment() method that increases self.count by 1.
-
A display() method that prints self.count.
Test it with:
counter1 = Counter() counter2 = Counter() counter1.increment() counter1.increment() counter2.increment() counter1.display() counter2.display()
Expected output:
2 1
As you trace each call, ask: “Which object does self refer to right now?” That tells you exactly which object’s count will be read or updated.