In the previous lessons, you learned how to create classes and objects, initialize objects using the __init__() constructor, and store data using instance variables. You also learned that methods allow objects to perform actions on their own data.
Now we will explore instance methods in more detail. Instance methods are the most commonly used type of method in Python classes. They are directly connected to individual objects and can access or modify the data belonging to those objects.
To understand instance methods properly, you must first understand the relationship between an object, its instance variables, and the self parameter.
An instance method is a method defined inside a class that operates on a particular object or instance of that class.
The first parameter of an instance method is conventionally written as self.
For example:
class Student:
def display(self):
print("Student details")
Here, display() is an instance method because it is designed to operate on a particular Student object.
We can create an object:
student1 = Student()
Then call the method:
student1.display()
Output:
Student details
The important point is that the method is called through an object.
The most important concept in an instance method is self.
self refers to the current object on which the method is operating.
Consider:
class Student:
def display(self):
print(self.name)
Now create an object:
student1 = Student()
student1.name = "Rahul"
student1.display()
Output:
Rahul
When student1.display() is called, self refers to student1.
Therefore:
self.name
effectively refers to:
student1.name
This allows the same method to work with different objects.
Suppose we create two students:
class Student:
def display(self):
print("Name:", self.name)
print("Course:", self.course)
student1 = Student()
student1.name = "Rahul"
student1.course = "Python"
student2 = Student()
student2.name = "Priya"
student2.course = "Data Analytics"
Now call the same method:
student1.display()
student2.display()
Output:
Name: Rahul
Course: Python
Name: Priya
Course: Data Analytics
The method definition is written only once, but it works with both objects.
When the first object calls the method:
student1.display()
self refers to student1.
When the second object calls the method:
student2.display()
self refers to student2.
This is one of the major benefits of instance methods.
Instance methods are particularly useful because they can directly access instance variables.
For example:
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def display(self):
print("Name:", self.name)
print("Salary:", self.salary)
Create an employee:
employee1 = Employee("Amit", 50000)
Call the instance method:
employee1.display()
Output:
Name: Amit
Salary: 50000
The method accesses:
self.name
self.salary
These values belong to the current employee object.
An instance method can do more than read an object’s data. It can also modify the object’s state.
Consider a bank account:
class BankAccount:
def __init__(self, account_holder, balance):
self.account_holder = account_holder
self.balance = balance
def deposit(self, amount):
self.balance += amount
Create an account:
account1 = BankAccount("Rahul", 50000)
Check the initial balance:
print(account1.balance)
Output:
50000
Now use the instance method:
account1.deposit(10000)
Check the balance again:
print(account1.balance)
Output:
60000
The method changed the state of account1.
This is a very important pattern:
Object
↓
Instance Variables
↓
Instance Method
↓
Read or Modify Object State
An instance method can accept additional parameters besides self.
For example:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def calculate_total(self, quantity):
return self.price * quantity
Create an object:
product1 = Product("Laptop", 55000)
Now call the method:
total = product1.calculate_total(3)
print(total)
Output:
165000
Here:
self
↓
Represents product1
quantity
↓
Additional value supplied to the method
The method combines information stored in the object with information supplied when the method is called.
Instance methods can return values just like normal Python functions.
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
Create an object:
rectangle1 = Rectangle(10, 5)
Call the method:
result = rectangle1.area()
print(result)
Output:
50
The method uses the object’s own length and width values and returns the calculated result.
Instance methods can also contain conditions based on the object’s current state.
For example:
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def is_passed(self):
if self.marks >= 40:
return True
else:
return False
Create two students:
student1 = Student("Rahul", 85)
student2 = Student("Amit", 32)
Check their results:
print(student1.is_passed())
print(student2.is_passed())
Output:
True
False
The same instance method produces different results because it operates on different object data.
An instance method can call another method of the same object using self.
For example:
class Student:
def __init__(self, name, marks):
self.name = name
self.marks = marks
def is_passed(self):
return self.marks >= 40
def display_result(self):
print("Name:", self.name)
print("Marks:", self.marks)
if self.is_passed():
print("Result: Passed")
else:
print("Result: Failed")
Create an object:
student1 = Student("Rahul", 85)
Call:
student1.display_result()
Output:
Name: Rahul
Marks: 85
Result: Passed
Notice that inside display_result(), we call:
self.is_passed()
This means the current object calls its own is_passed() method.
Let’s create a more complete employee class.
class Employee:
def __init__(self, employee_id, name, salary):
self.employee_id = employee_id
self.name = name
self.salary = salary
def annual_salary(self):
return self.salary * 12
def apply_raise(self, percentage):
increase = self.salary * percentage / 100
self.salary += increase
def display(self):
print("ID:", self.employee_id)
print("Name:", self.name)
print("Salary:", self.salary)
Create an employee:
employee1 = Employee(
101,
"Rahul",
50000
)
Display the information:
employee1.display()
Calculate annual salary:
print(employee1.annual_salary())
Apply a raise:
employee1.apply_raise(10)
Display the updated information:
employee1.display()
Output:
ID: 101
Name: Rahul
Salary: 50000
600000
ID: 101
Name: Rahul
Salary: 55000.0
This example shows several uses of instance methods:
display() reads object data.annual_salary() calculates a value using object data.apply_raise() modifies object data.Each object maintains its own instance state.
employee1 = Employee(101, "Rahul", 50000)
employee2 = Employee(102, "Priya", 60000)
Now:
employee1.apply_raise(10)
Only employee1‘s salary changes.
employee2‘s salary remains unchanged.
print(employee1.salary)
print(employee2.salary)
Output:
55000.0
60000
This happens because self refers to the specific object that called the method.
Beginners sometimes wonder whether an instance method can be called through the class.
Consider:
class Student:
def display(self):
print(self.name)
Normally we write:
student1.display()
This is the normal and recommended way to call an instance method.
Python conceptually passes the object as the first argument.
You can think of:
student1.display()
as being closely related to:
Student.display(student1)
The second form makes it easier to understand why self exists, although in normal code the first form is preferred.
An instance method is technically a function defined inside a class that operates on an instance.
Compare:
def calculate_area(length, width):
return length * width
with:
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
The standalone function receives all required data explicitly.
The instance method already has access to the object’s data through self.
This can make the relationship between data and behavior clearer when the data and operation naturally belong together.
self in an instance method definition.self when accessing instance variables.self.name with a local variable called name.self refers to the class rather than the current object.self.self refers to the current object.self.Instance methods are the foundation for understanding the other method types in Python OOP. In the next part, we will move from object-level behavior to class-level behavior and learn how @classmethod and the cls parameter work.
In the previous part, you learned about instance methods. Instance methods operate on individual objects and use the self parameter to access or modify data belonging to that particular object.
For example, if every employee has a different name and salary, those values belong to individual employee objects:
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def display(self):
print(self.name, self.salary)
Here, self.name and self.salary belong to each individual object.
But sometimes we need data or behavior that belongs to the class itself, rather than to one particular object. This is where class methods become useful.
A class method works with the class rather than being primarily tied to one specific instance. Python provides the @classmethod decorator for defining class methods.
A class method is a method that receives the class itself as its first argument instead of an individual object.
By convention, that first parameter is called cls.
The basic syntax is:
class MyClass:
@classmethod
def method_name(cls):
# class-level logic
pass
There are two important parts here:
@classmethod tells Python that the method should behave as a class method.cls refers to the current class.Just as self conventionally represents the current object, cls conventionally represents the current class.
A useful way to remember the difference is:
self
↓
Current Object
cls
↓
Current Class
Let’s create a simple class:
class Student:
school_name = "Vista Academy"
@classmethod
def show_school(cls):
print("School:", cls.school_name)
Here, school_name is associated with the class.
We can call the class method directly using the class:
Student.show_school()
Output:
School: Vista Academy
Notice that we did not create a student object.
We did not write:
student1 = Student()
Instead, we directly used:
Student.show_school()
This is possible because the method is associated with the class.
Consider the following example:
class Student:
school_name = "Vista Academy"
@classmethod
def show_school(cls):
print(cls.school_name)
When we call:
Student.show_school()
the cls parameter refers to the Student class.
Therefore:
cls.school_name
refers to:
Student.school_name
Conceptually:
Student.show_school()
↓
cls
↓
Student class
↓
school_name
This is similar to how an instance method uses self:
student1.display()
↓
self
↓
student1 object
The key difference is whether the method is operating at the object level or the class level.
Class methods are especially useful when working with class variables.
A class variable is a variable associated with the class rather than a particular object.
class Employee:
company = "ABC Technologies"
@classmethod
def show_company(cls):
print(cls.company)
Now call:
Employee.show_company()
Output:
ABC Technologies
We can create employees as well:
employee1 = Employee()
employee2 = Employee()
Both objects can access the class variable:
print(employee1.company)
print(employee2.company)
Both will refer to the class-level company information.
The class method can also access the same value:
Employee.show_company()
This makes class methods useful for operations that concern the class as a whole.
A class method can also modify class-level data.
class Employee:
company = "ABC Technologies"
@classmethod
def change_company(cls, new_company):
cls.company = new_company
Initially:
print(Employee.company)
Output:
ABC Technologies
Now call:
Employee.change_company("XYZ Solutions")
Check the value again:
print(Employee.company)
Output:
XYZ Solutions
The class method changed the class-level value through cls.
The important statement is:
cls.company = new_company
Because cls represents the class, this operation changes the class-level attribute.
Compare these two methods:
class Employee:
company = "ABC Technologies"
def display_employee(self):
print("Employee method")
@classmethod
def display_company(cls):
print("Company:", cls.company)
The first method:
display_employee(self)
is an instance method.
It operates on a particular employee object.
The second:
display_company(cls)
is a class method.
It operates on the class.
We normally call them like this:
employee1.display_employee()
Employee.display_company()
The mental model is:
Instance Method
↓
self
↓
Current Object
Class Method
↓
cls
↓
Current Class
A class method can also be accessed through an instance:
employee1.display_company()
However, the purpose of a class method is to work with class-level information, so calling it through the class often makes the intention clearer:
Employee.display_company()
This makes it immediately visible that the operation concerns the class rather than a specific employee.
One of the most useful applications of class methods is creating alternative constructors.
Suppose we have a Student class:
class Student:
def __init__(self, name, age, course):
self.name = name
self.age = age
self.course = course
Normally we create an object by supplying the values directly:
student1 = Student(
"Rahul",
21,
"Python"
)
But suppose the information is available in a different format, such as a string:
"Rahul,21,Python"
We could create a class method that converts this string into the required arguments.
class Student:
def __init__(self, name, age, course):
self.name = name
self.age = age
self.course = course
@classmethod
def from_string(cls, data):
name, age, course = data.split(",")
return cls(
name,
int(age),
course
)
Now we can create an object from the string:
student1 = Student.from_string(
"Rahul,21,Python"
)
We can display the values:
print(student1.name)
print(student1.age)
print(student1.course)
Output:
Rahul
21
Python
This is a powerful use of @classmethod.
Instead of replacing the normal constructor, the class method provides another convenient way of creating objects.
You might wonder why we write:
return cls(name, age, course)
instead of:
return Student(name, age, course)
Using cls makes the method more flexible.
It refers to the class on which the method is being used. This becomes particularly valuable when inheritance is introduced later in Python OOP.
For now, remember the simple rule:
self → current instance
cls → current class
Consider an employee class:
class Employee:
def __init__(self, name, department, salary):
self.name = name
self.department = department
self.salary = salary
@classmethod
def from_string(cls, data):
name, department, salary = data.split(",")
return cls(
name,
department,
float(salary)
)
Now suppose employee information arrives as:
data = "Priya,Analytics,65000"
We can create the object using:
employee1 = Employee.from_string(data)
Then:
print(employee1.name)
print(employee1.department)
print(employee1.salary)
Output:
Priya
Analytics
65000.0
The class method converted the input format and created a properly initialized object.
Another practical use of class variables and class methods is maintaining information shared across objects.
For example, suppose we want to count how many employee objects have been created.
class Employee:
employee_count = 0
def __init__(self, name):
self.name = name
Employee.employee_count += 1
@classmethod
def total_employees(cls):
return cls.employee_count
Create some employees:
employee1 = Employee("Rahul")
employee2 = Employee("Priya")
employee3 = Employee("Amit")
Now:
print(Employee.total_employees())
Output:
3
The count is associated with the class rather than one individual employee.
The class method accesses it through:
cls.employee_count
This is different from an instance variable such as:
self.name
because each employee has a different name, while the employee count represents information about the group as a whole.
| Instance Variable | Class Variable |
|---|---|
| Belongs to an individual object | Associated with the class |
Usually accessed through self |
Often accessed through cls or the class name |
| Can have different values for each object | Can provide shared class-level information |
Example: self.name |
Example: cls.company |
For example:
class Employee:
company = "ABC Technologies"
def __init__(self, name):
self.name = name
Here:
company
is class-level information, while:
self.name
belongs to each individual employee.
Class methods can also be useful when a class needs to update shared configuration.
class Application:
version = "1.0"
@classmethod
def update_version(cls, new_version):
cls.version = new_version
Initially:
print(Application.version)
Output:
1.0
Update it:
Application.update_version("2.0")
Now:
print(Application.version)
Output:
2.0
The operation concerns the class as a whole, so a class method is appropriate.
A class method is useful when the operation primarily concerns the class rather than an individual object.
Common situations include:
For example, if you need a method to calculate something using a specific student’s personal marks, an instance method is generally appropriate.
If you need a method to create a student from a particular input format, a class method can be useful.
@classmethod decorator.self instead of cls when defining a class method.cls when writing reusable class methods.For example, this is incorrect for a class method:
class Employee:
@classmethod
def show_company(self):
print(self.company)
Although Python allows parameter names other than cls, using cls is the standard convention and makes the purpose immediately clear.
The preferred version is:
class Employee:
@classmethod
def show_company(cls):
print(cls.company)
| Feature | Instance Method | Class Method |
|---|---|---|
| Decorator | None required | @classmethod |
| First parameter | self |
cls |
| Works primarily with | Individual object | Class |
| Accesses | Instance variables | Class variables |
| Typical call | object.method() |
Class.method() |
| Common use | Object behavior | Class-level behavior and alternative constructors |
@classmethod decorator is used to define one.cls.cls refers to the current class.cls makes alternative constructors more flexible.At this stage, you should be able to distinguish the two concepts clearly:
Instance Method
↓
self
↓
Current Object
Class Method
↓
cls
↓
Current Class
In the next part, we will learn about the third major method type in this lesson: the static method. You will see why a static method does not require either self or cls, how @staticmethod works, and how to decide whether a task belongs to an instance method, class method, or static method.
In the previous parts, you learned about two important types of methods in Python: instance methods and class methods. Instance methods use self to work with a particular object, while class methods use cls to work with the class itself.
Python provides a third important method type called a static method. A static method is different because it does not need access to either a particular object or the class itself.
This makes static methods useful for placing related utility operations inside a class without requiring object-specific or class-specific information.
A static method is a method defined inside a class that does not automatically receive self or cls as its first parameter.
Python uses the @staticmethod decorator to define a static method.
The basic syntax is:
class MyClass:
@staticmethod
def method_name():
# method logic
pass
Notice that there is no self parameter and no cls parameter.
This gives us a simple way to remember the three method types:
Instance Method
↓
self
↓
Current Object
Class Method
↓
cls
↓
Current Class
Static Method
↓
No self / cls
↓
Independent Utility Logic
Let’s create a simple utility method:
class Calculator:
@staticmethod
def add(a, b):
return a + b
We can call the method directly through the class:
result = Calculator.add(10, 20)
print(result)
Output:
30
Notice that we did not create an object:
calculator1 = Calculator()
We simply used:
Calculator.add(10, 20)
The method does not need any information about a particular calculator object or the Calculator class itself. It only needs the two values supplied as arguments.
Sometimes a function is logically related to a class but does not need to access any object or class data.
For example, suppose we have a Student class and want to check whether a marks value is valid.
class Student:
@staticmethod
def valid_marks(marks):
return 0 <= marks <= 100
We can call it directly:
print(Student.valid_marks(85))
print(Student.valid_marks(120))
Output:
True
False
The method does not need a particular student object.
It does not use:
self.name
self.marks
self.course
It also does not need class-level information.
It simply receives a value and returns a result.
You may wonder why we don’t simply write:
def valid_marks(marks):
return 0 <= marks <= 100
That is a perfectly valid approach.
The reason to place it inside the Student class is organizational. The operation is conceptually related to students, so keeping it with the Student class can make the code easier to understand.
For example:
Student.valid_marks(85)
immediately communicates that the validation is related to student marks.
A static method therefore provides a way to keep related utility functionality inside an appropriate class without pretending that the function needs object or class state.
Consider this instance method:
class Calculator:
def multiply(self, a, b):
return a * b
It has:
self
because it is an instance method.
Now compare it with:
class Calculator:
@staticmethod
def multiply(a, b):
return a * b
There is no self.
We can call it:
Calculator.multiply(5, 4)
Output:
20
The method receives only the parameters explicitly supplied by the caller.
A class method uses:
@classmethod
def show_company(cls):
print(cls.company)
A static method does not automatically receive cls.
@staticmethod
def add(a, b):
return a + b
There is no automatic reference to the class.
This means a static method is appropriate when the operation does not need information from either the individual object or the class.
Let’s build a calculator class containing several static methods.
class Calculator:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def subtract(a, b):
return a - b
@staticmethod
def multiply(a, b):
return a * b
@staticmethod
def divide(a, b):
if b == 0:
return "Cannot divide by zero"
return a / b
Now we can use the methods:
print(Calculator.add(10, 5))
print(Calculator.subtract(10, 5))
print(Calculator.multiply(10, 5))
print(Calculator.divide(10, 5))
Output:
15
5
50
2.0
None of these calculations requires a particular calculator object’s data.
Therefore, static methods are a reasonable design choice.
Static methods are often useful for validation functions.
Consider an email validation example:
class User:
@staticmethod
def valid_email(email):
return "@" in email
Now:
print(User.valid_email("rahul@example.com"))
print(User.valid_email("rahulexample.com"))
Output:
True
False
The method does not need a User object. It only needs the email value supplied as an argument.
In a real application, email validation would normally be more sophisticated, but this example demonstrates the role of a static method.
A class can contain instance methods, class methods, and static methods together.
class Employee:
company = "ABC Technologies"
def __init__(self, name, salary):
self.name = name
self.salary = salary
def display(self):
print("Name:", self.name)
print("Salary:", self.salary)
@classmethod
def show_company(cls):
print("Company:", cls.company)
@staticmethod
def valid_salary(salary):
return salary >= 0
Now the class contains three different types of behavior.
The instance method:
display()
uses individual employee information.
The class method:
show_company()
uses class-level information.
The static method:
valid_salary()
performs a general validation operation without needing either object or class state.
Let’s use the previous class.
employee1 = Employee(
"Rahul",
50000
)
Call the instance method:
employee1.display()
Call the class method:
Employee.show_company()
Call the static method:
print(Employee.valid_salary(50000))
Output:
Name: Rahul
Salary: 50000
Company: ABC Technologies
True
This example demonstrates the basic distinction between the three method types.
A static method does not require an object to be called.
For example:
class Temperature:
@staticmethod
def celsius_to_fahrenheit(celsius):
return (celsius * 9 / 5) + 32
Call it directly:
print(
Temperature.celsius_to_fahrenheit(25)
)
Output:
77.0
There is no need to create:
temperature1 = Temperature()
because the calculation does not depend on any temperature object’s stored state.
A static method is appropriate when:
Examples include:
If a method needs information belonging to a particular object, an instance method is generally more appropriate.
For example:
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def annual_salary(self):
return self.salary * 12
annual_salary() needs:
self.salary
Therefore, it should be an instance method rather than a static method.
Similarly, if a method needs class-level information such as:
cls.company
then a class method may be more appropriate.
| Feature | Instance Method | Static Method |
|---|---|---|
| Decorator | None | @staticmethod |
| First parameter | self |
None required |
| Needs object data? | Usually yes | No |
| Can access instance variables? | Yes | Not automatically |
| Typical purpose | Object behavior | Utility behavior |
| Feature | Class Method | Static Method |
|---|---|---|
| Decorator | @classmethod |
@staticmethod |
| First parameter | cls |
None required |
| Accesses class data? | Yes | Not automatically |
| Accesses object data? | Not through self |
No automatic object access |
| Typical purpose | Class-level operations | Independent utility operations |
When deciding which method type to use, ask one simple question:
What data does this method need?
If it needs data belonging to a particular object:
Use Instance Method
↓
self
If it needs data belonging to the class:
Use Class Method
↓
cls
If it needs neither object data nor class data:
Use Static Method
↓
No self / cls
This rule will help you decide correctly in most beginner and intermediate OOP situations.
@staticmethod decorator.self unnecessarily.cls unnecessarily.For example, this is unnecessarily written as an instance method:
class Calculator:
def add(self, a, b):
return a + b
If the calculation does not need any object state, a static method may communicate the intent better:
class Calculator:
@staticmethod
def add(a, b):
return a + b
@staticmethod.self.cls.You now know all three major method types used in Python OOP: instance methods, class methods, and static methods. In the final part, we will compare all three side by side and apply them together in practical examples, exercises, interview questions, and a mini project.
In this lesson, you have learned the three major types of methods used in Python classes: instance methods, class methods, and static methods. The most important skill now is knowing how to distinguish them and deciding which one should be used for a particular task.
Although all three methods are defined inside a class, they serve different purposes. The difference mainly depends on what information the method needs and whether the operation belongs to an individual object, the class itself, or neither.
| Feature | Instance Method | Class Method | Static Method |
|---|---|---|---|
| Decorator | None | @classmethod |
@staticmethod |
| First parameter | self |
cls |
None required |
| Works with | Individual object | Class | Neither specifically |
| Accesses instance variables | Yes | Not through self |
No automatic access |
| Accesses class variables | Can access them | Yes | No automatic access |
| Usually called through | Object | Class | Class |
| Typical purpose | Object behavior | Class-level behavior | Utility behavior |
A simple way to remember the difference is:
Instance Method
↓
self
↓
Individual Object
Class Method
↓
cls
↓
Class
Static Method
↓
No self / cls
↓
Independent Utility
Let’s create one practical example containing an instance method, class method, and static method.
class Employee:
company = "ABC Technologies"
def __init__(self, name, salary):
self.name = name
self.salary = salary
def display(self):
print("Name:", self.name)
print("Salary:", self.salary)
@classmethod
def show_company(cls):
print("Company:", cls.company)
@staticmethod
def valid_salary(salary):
return salary >= 0
Now create an employee:
employee1 = Employee(
"Rahul",
50000
)
The constructor creates the object’s initial state.
The instance method can display that individual employee:
employee1.display()
Output:
Name: Rahul
Salary: 50000
The class method can display information about the company:
Employee.show_company()
Output:
Company: ABC Technologies
The static method can validate a salary:
print(Employee.valid_salary(50000))
Output:
True
Each method has a different responsibility even though all three belong to the same class.
When designing a class, ask what information the method actually needs.
If the method needs information belonging to a particular object, use an instance method.
def display(self):
print(self.name)
If the method needs information belonging to the class, use a class method.
@classmethod
def show_company(cls):
print(cls.company)
If the method needs neither object information nor class information, a static method may be appropriate.
@staticmethod
def add(a, b):
return a + b
This decision process can be represented as:
Does the method need object data?
↓
Yes
↓
Instance Method
No
↓
Does it need class data?
↓
Yes
↓
Class Method
No
↓
Static Method
Let’s apply all three methods to a student management example.
class Student:
school = "Vista Academy"
student_count = 0
def __init__(self, name, marks):
self.name = name
self.marks = marks
Student.student_count += 1
def display(self):
print("Name:", self.name)
print("Marks:", self.marks)
@classmethod
def show_school(cls):
print("School:", cls.school)
@classmethod
def total_students(cls):
return cls.student_count
@staticmethod
def valid_marks(marks):
return 0 <= marks <= 100
Create students:
student1 = Student("Rahul", 92)
student2 = Student("Priya", 88)
student3 = Student("Amit", 76)
Now we have three different objects.
Use the instance method:
student1.display()
Output:
Name: Rahul
Marks: 92
The instance method uses:
self.name
self.marks
Now use the class method:
Student.show_school()
Output:
School: Vista Academy
This method uses:
cls.school
Now find the number of students:
print(Student.total_students())
Output:
3
Finally, use the static method:
print(Student.valid_marks(85))
print(Student.valid_marks(150))
Output:
True
False
This example demonstrates the three different levels of responsibility clearly.
The display() method belongs to individual student objects because every student has different information.
For example:
student1.display()
student2.display()
can produce different results.
The show_school() method belongs to the class because the school information is shared by the class.
The total_students() method also works at the class level because the count represents the collection of students created through the class.
The valid_marks() method does not need either a particular student or class-level data. It only needs the marks supplied to it, so it is suitable as a static method.
Another important application of class methods is creating objects from alternative input formats.
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
@classmethod
def from_string(cls, data):
name, price = data.split(",")
return cls(
name,
float(price)
)
Now we can create a product normally:
product1 = Product(
"Laptop",
55000
)
Or use the alternative constructor:
product2 = Product.from_string(
"Mobile,25000"
)
Now:
print(product2.name)
print(product2.price)
Output:
Mobile
25000.0
The class method provides an alternative way of creating an object while still ultimately using the class constructor.
Create a BankAccount class with the following requirements:
account_holderbalanceCreate these methods:
deposit() that changes the balance.withdraw() that reduces the balance.Your starting structure should look like:
class BankAccount:
bank_name = "ABC Bank"
def __init__(self, account_holder, balance):
self.account_holder = account_holder
self.balance = balance
# Add your instance methods here
# Add your class method here
# Add your static method here
Try completing this yourself before looking for a solution.
Create an Employee class with:
Create:
Think carefully about why each method belongs to its particular category.
Create a Temperature class with static methods for:
Ask yourself: does any of these conversions require information stored inside a particular temperature object?
If not, static methods are a suitable choice.
Mistake 1: Using a static method when object data is required
If the method needs:
self.salary
then it is normally an instance method.
Mistake 2: Using an instance method for class-level information
If the operation concerns something shared by the entire class, a class method may be more appropriate.
Mistake 3: Thinking static means the method cannot accept parameters
A static method can accept as many normal parameters as necessary:
@staticmethod
def calculate(a, b, c):
return a + b + c
The difference is that Python does not automatically supply self or cls.
Mistake 4: Using class methods everywhere
Not every method that belongs to a class should be a class method. Choose the method type according to the data and responsibility involved.
Mistake 5: Assuming static methods are always better
A static method is useful only when the operation genuinely does not need object or class state. If the method needs self or cls, use the appropriate method type instead.
1. What is an instance method?
An instance method operates on a particular object and normally receives self as its first parameter.
2. What is a class method?
A class method operates at the class level and receives cls as its first parameter.
3. Which decorator is used for a class method?
@classmethod.
4. Which decorator is used for a static method?
@staticmethod.
5. Does a static method receive self automatically?
No.
6. Does a static method receive cls automatically?
No.
7. What does self represent?
The current object or instance.
8. What does cls represent?
The current class.
9. When should you use a static method?
When the operation is logically related to the class but does not require instance or class state.
10. Can one class contain all three types of methods?
Yes. A class can contain instance methods, class methods, and static methods together.
The three method types can now be summarized very simply.
1. Instance Method
def method(self):
...
Used for:
Object-specific behavior
2. Class Method
@classmethod
def method(cls):
...
Used for:
Class-level behavior
3. Static Method
@staticmethod
def method():
...
Used for:
Independent utility behavior
The most useful question to ask when designing a method is:
“What data does this method need?”
If it needs data belonging to one object, use an instance method.
If it needs data belonging to the class, use a class method.
If it needs neither, consider a static method.
This distinction will become even more important when you start learning inheritance and more advanced OOP concepts.
As a final exercise, build an Employee Management System using all three method types.
The class should contain:
Implement:
A possible structure is:
class Employee:
company = "ABC Technologies"
employee_count = 0
def __init__(self, employee_id, name, salary):
self.employee_id = employee_id
self.name = name
self.salary = salary
Employee.employee_count += 1
def display(self):
pass
def annual_salary(self):
pass
def apply_raise(self, percentage):
pass
@classmethod
def show_company(cls):
pass
@classmethod
def total_employees(cls):
pass
@staticmethod
def valid_salary(salary):
pass
Try implementing the missing methods yourself. The goal is not simply to copy a completed program but to understand why each method belongs where it does.
In this lesson, you learned the three major types of methods in Python OOP.
Instance methods work with individual objects and use self. They are appropriate when a method needs to read or modify instance variables such as an employee’s salary or a student’s marks.
Class methods work with the class itself and use cls. They are useful for class-level information, class variables, counters, configuration, and alternative constructors.
Static methods do not automatically receive either self or cls. They are useful for utility operations that are logically related to the class but do not require object or class state.
The key distinction is:
self → object
cls → class
no self / cls → static utility
Once you understand this distinction, you can design Python classes more cleanly and choose the appropriate method type based on what the method actually needs.
With instance, class, and static methods now covered, the next lesson will introduce another major OOP concept: Encapsulation in Python, where you will learn how to control access to object data and why names such as public, protected, and private are important in Python class design.