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.

Previous Topic Classes and Objects Next Topic Types of Variables