Initializing Objects and Adding Methods
Python Classes and Objects: Initializing Objects and Adding Methods
In the previous lesson, we created student objects and assigned their details individually.
class Student:
pass
student1 = Student()
student1.name = "Rahul"
student1.roll_number = 101
student1.marks = 85
Every time we create another student, we repeat the same assignments. We might also forget to assign an attribute before accessing it.
We can move these assignments inside the class and provide the values while creating each object.
Initializing a Student Object
Python provides a special method named __init__(). It runs automatically to initialize a newly created instance.
class Student:
def __init__(self, name, roll_number, marks):
self.name = name
self.roll_number = roll_number
self.marks = marks
Notice the indentation: __init__() is defined inside the class, and the three assignments are inside __init__().
We can now create a student like this:
student1 = Student("Rahul", 101, 85)
Then access the attributes as before:
print("Name:", student1.name)
print("Roll Number:", student1.roll_number)
print("Marks:", student1.marks)
Output:
Name: Rahul Roll Number: 101 Marks: 85
The object receives its initial data as part of the creation process.
The name __init__ has two underscores before and after init. The spelling must be exact.
Although it is often called a constructor in introductory discussions, __init__() specifically initializes an instance after it has been created.
Following the Values into the Object
Consider the statement:
student1 = Student("Rahul", 101, 85)
Python creates a Student instance and automatically calls its __init__() method with the supplied values.
| Parameter | Receives |
|---|---|
| self | The newly created instance |
| name | "Rahul" |
| roll_number | 101 |
| marks | 85 |
Inside the method:
self.name = name
The two uses of name have different roles:
-
name is a parameter containing the supplied value.
-
self.name is an attribute belonging to the object.
The assignment stores the parameter’s value in the object.
The other assignments follow the same pattern:
self.roll_number = roll_number self.marks = marks
Once initialization finishes, student1 refers to the initialized object.
Understanding self with Two Objects
Let us create two students:
student1 = Student("Rahul", 101, 85)
student2 = Student("Anjali", 102, 92)
During the first initialization, self refers to the instance that will be assigned to student1. During the second initialization, it refers to the instance that will be assigned to student2.
The same method therefore initializes different objects with different values.
print(student1.name, student1.marks) print(student2.name, student2.marks)
Output:
Rahul 85 Anjali 92
We do not pass self explicitly:
student1 = Student("Rahul", 101, 85)
Python supplies the instance automatically.
self is a naming convention, not a Python keyword. Use this conventional name consistently so that your code is easy to understand.
Adding an Action to the Class
Our objects now store student details. We can also define actions that work with those details.
A function defined inside a class is called a method.
Let us add a method to display a student’s information:
class Student:
def __init__(self, name, roll_number, marks):
self.name = name
self.roll_number = roll_number
self.marks = marks
def display_details(self):
print("Name:", self.name)
print("Roll Number:", self.roll_number)
print("Marks:", self.marks)
Both methods are indented at the same level inside the class.
We call the new method using dot notation followed by parentheses:
student1 = Student("Rahul", 101, 85)
student1.display_details()
Output:
Name: Rahul Roll Number: 101 Marks: 85
When we call:
student1.display_details()
Python passes student1 as the self argument. Inside the method, self.name, self.roll_number, and self.marks access that student’s attributes.
For this method, the call can also be written as:
Student.display_details(student1)
Both forms produce the same result. The first form is the usual way to call an instance method.
Calling the Same Method on Different Objects
We do not need a separate display method for every student.
student1 = Student("Rahul", 101, 85)
student2 = Student("Anjali", 102, 92)
student1.display_details()
print()
student2.display_details()
Output:
Name: Rahul Roll Number: 101 Marks: 85 Name: Anjali Roll Number: 102 Marks: 92
The method uses the data of the object on which it is called.
Returning a Result
Suppose our example uses a pass mark of 40. We can add a method that checks the student’s marks and returns a result.
Add this method inside the Student class:
def get_result(self):
if self.marks >= 40:
return "Pass"
return "Fail"
We can store the returned value in a variable:
student1 = Student("Rahul", 101, 85)
result = student1.get_result()
print("Result:", result)
Output:
Result: Pass
Returning the result makes it available for further processing.
if student1.get_result() == "Pass":
print("Eligible for the next level.")
Output:
Eligible for the next level.
The two methods serve different purposes:
| Method | Behavior |
|---|---|
| display_details() | Prints information on the screen |
| get_result() | Returns a value that other code can use |
A method without an explicit return statement returns None. Therefore:
value = student1.display_details() print(value)
prints the student’s details, followed by:
None
Use print() when the method should display something. Use return when the calling code needs a result.
Updating Data through a Method
Previously, we changed marks directly:
student1.marks = 90
We can also provide a method for updating them.
Add this method inside the class:
def update_marks(self, new_marks):
self.marks = new_marks
Call it with the new value:
student1.update_marks(90)
print("Updated Marks:", student1.marks)
Output:
Updated Marks: 90
In this call:
student1.update_marks(90)
self receives the student object automatically, while new_marks receives 90.
Because get_result() reads the object’s current marks each time, its result reflects any update.
student2 = Student("Anjali", 102, 35)
print("Before Update:", student2.get_result())
student2.update_marks(65)
print("After Update:", student2.get_result())
Output:
Before Update: Fail After Update: Pass
Complete Program
The following program brings initialization and the three methods together:
class Student:
def __init__(self, name, roll_number, marks):
self.name = name
self.roll_number = roll_number
self.marks = marks
def display_details(self):
print("Name:", self.name)
print("Roll Number:", self.roll_number)
print("Marks:", self.marks)
def get_result(self):
if self.marks >= 40:
return "Pass"
return "Fail"
def update_marks(self, new_marks):
self.marks = new_marks
student1 = Student("Rahul", 101, 85)
student2 = Student("Anjali", 102, 35)
print("Student 1")
student1.display_details()
print("Result:", student1.get_result())
print()
print("Student 2")
student2.display_details()
print("Result:", student2.get_result())
student2.update_marks(65)
print()
print("Student 2 After Updating Marks")
student2.display_details()
print("Result:", student2.get_result())
Output:
Student 1 Name: Rahul Roll Number: 101 Marks: 85 Result: Pass Student 2 Name: Anjali Roll Number: 102 Marks: 35 Result: Fail Student 2 After Updating Marks Name: Anjali Roll Number: 102 Marks: 65 Result: Pass
Our update method currently assigns the supplied value directly. We will introduce validation when we cover controlled access to object data.
A Few Details to Watch While Coding
Inside an instance method, use self to access the object’s attributes.
def display_details(self):
print(self.name)
Writing print(name) does not automatically access the object’s name attribute. The name parameter from __init__() is local to that method.
Also, remember the parentheses when calling a method:
student1.display_details() # Calls the method
Without parentheses, you only access the method:
student1.display_details
Finally, our current initializer requires three values:
student1 = Student("Rahul", 101, 85)
Calling Student() without them raises a TypeError because the required arguments are missing.
In the next lesson, we will examine the variables in these classes more closely: data belonging to each instance, data shared through the class, and local variables used inside methods.