Class Methods, Static Methods, and Instance Methods in Python

Python provides three types of methods in a class: Instance Methods, Class Methods, and Static Methods. Each serves a different purpose and is used based on the requirement. In this article, we’ll explore these methods with examples to understand their differences and use cases.

class method static method instance method

Instance Methods

Instance methods are the most commonly used methods in a class. They have access to both instance variables (attributes) and class variables. They require an instance of the class to be called.

Characteristics:

  • Defined using def with self as the first parameter.
  • Can modify the object’s state (instance attributes).
  • Can access and modify class-level data.

Example 1: Basic

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def greet(self):
        return f"Hello, my name is {self.name} and I am {self.age} years old."

# Creating an instance
person = Person("Alice", 25)
print(person.greet())  # Output: Hello, my name is Alice and I am 25 years old.
Python

Example 2 A: Instance method accessing class variables

class MyClass:
    class_var = 10  # This is a class variable

    def __init__(self, value):
        self.instance_var = value  # Instance variable

    def print_vars(self):
        print("Class Variable (via class):", MyClass.class_var) #correct way
        print("Class Variable (via self):", self.class_var) #working, but don't use like this
        print("Instance Variable:", self.instance_var)

obj = MyClass(5)
obj.print_vars()
Python

Example 2 B Strange

class my_class:
    
    counter = 0
    def abc(self):
        self.counter+=1 #refering to instance variable 

    @classmethod
    def xyz(cls):
        print(cls.counter)

    @staticmethod
    def d():
        print(my_class.counter)

obj1 = my_class()
obj2 = my_class()
obj1.abc()
obj2.abc()

obj1.xyz()

my_class().d()

'''
0
0
'''
Python

Why

  • Above code, does not modify the class variable counter, while in code 2A its refering to class variable
  • Instead, it creates an instance variable counter for self (i.e., obj1 or obj2) if it doesn’t already exist, and modifies that.

Reason

  • 2A: Accessing self.class_var → Python looks up the class if it’s not on the instance.
  • 2B: Assigning to self.class_var = … → Python creates an instance attribute, shadowing the class one.

So to avoid confusion alway use class_name.class_variable

When to Use:

  • When you need to work with instance attributes.
  • When the method behavior depends on the individual object.

Class Methods

Class methods are used when we need to modify or access class-level attributes rather than instance attributes. They are bound to the class and receive cls (class reference) as the first parameter instead of self.

Characteristics:

  • Defined using @classmethod decorator
  • Takes cls as the first parameter
  • Can access and modify class attributes but cannot modify instance attributes
  • shared across all instances

Example:

class Car:
    wheels = 4  # Class attribute
    
    def __init__(self, brand):
        self.brand = brand
    
    @classmethod
    def set_wheels(cls, count):
        cls.wheels = count  # Modifies class attribute
    
    @classmethod
    def get_wheels(cls):
        return f"All cars have {cls.wheels} wheels."

# Modifying class attribute using class method
Car.set_wheels(6)
print(Car.get_wheels())  # Output: All cars have 6 wheels.
Python

When to Use:

  • When a method needs to operate on class variables rather than instance variables.
  • When alternative constructors are needed.

Alternative constructor:

A class method can be used as an alternative constructor to process the data and create an instance.

class Employee:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    @classmethod
    def alternative(cls, name, age):
        return cls(name, age)


emp_cons = Employee("Sam",45)
emp_alter = Employee.alternative("John",30)

print(type(emp_cons)) #<class '__main__.Employee'>
print(type(emp_alter)) #<class '__main__.Employee'>
Python

Static Methods

Static methods are independent of both class and instance attributes. They are used when we don’t need to modify class or instance attributes but still want to keep related functionality inside the class.

Characteristics:

  • Defined using @staticmethod decorator.
  • Do not take self or cls as the first parameter.
  • Can be called on an instance or class.

Example 1: Basic

class MathOperations:
    @staticmethod
    def add(x, y):
        return x + y
    
    @staticmethod
    def multiply(x, y):
        return x * y

# Calling static methods
print(MathOperations.add(5, 3))      # Output: 8
print(MathOperations.multiply(4, 6)) # Output: 24
Python

Example 2: Static methods can be called on an instance or class.

class MyClass:
    @staticmethod
    def greet():
        print("Hello from static method!")

# Calling on the class
MyClass.greet()

# Calling on an instance
obj = MyClass()
obj.greet()
Python

When to Use:

  • When a method does not depend on instance or class attributes.
  • For utility functions related to the class but do not require access to class/instance data.

Key Differences

FeatureInstance MethodClass MethodStatic Method
Bound toInstanceClassNeither
First Parameterself (instance)cls (class)No self or cls
Can Modify Instance Attributes?Yes No No
Can Modify Class Attributes?YesYesNo
Called UsingInstanceInstance or ClassInstance or Class

Real life Example

Bank Account System

  • Instance Method – Working with Object Attributes
  • Imagine a Bank Account where each customer has their own balance and can deposit or withdraw money.

class BankAccount:
    def __init__(self, account_holder, balance=0):
        self.account_holder = account_holder
        self.balance = balance  # Instance attribute

    def deposit(self, amount):
        self.balance += amount
        return f"Deposited {amount}. New Balance: {self.balance}"

    def withdraw(self, amount):
        if amount > self.balance:
            return "Insufficient funds!"
        self.balance -= amount
        return f"Withdrawn {amount}. Remaining Balance: {self.balance}"

# Real-Life Usage
account1 = BankAccount("Alice", 1000)
print(account1.deposit(500))    # Deposited 500. New Balance: 1500
print(account1.withdraw(2000))  # Insufficient funds!
print(account1.withdraw(300))   # Withdrawn 300. Remaining Balance: 1200
Python

Why use an instance method?

  • Each account has its own balance.
  • The deposit and withdraw methods modify the account’s balance, which is unique for every customer.

Counting Total Employees in a Company

  • Class Method – Managing Shared Data
  • Imagine a company where we need to track the total number of employees.
class Employee:
    total_employees = 0  # Class attribute (shared by all instances)

    def __init__(self, name):
        self.name = name
        Employee.total_employees += 1  # Updating shared data

    @classmethod
    def get_total_employees(cls):
        return f"Total Employees: {cls.total_employees}"

# Real-Life Usage
emp1 = Employee("John")
emp2 = Employee("Emma")
emp3 = Employee("Liam")

print(Employee.get_total_employees())  # Total Employees: 3

# We can use object as well
print(emp3.get_total_employees())  # Total Employees: 3
Python

Why use a class method?

  • total_employees is shared across all instances.
  • get_total_employees() provides a way to access and modify class-level data.

Example: Validating Emails for User Registration

  • Static Method – Utility Functions Inside a Class
  • Imagine an application where we need to validate user emails before creating an account.
import re

class User:
    def __init__(self, username, email):
        if not self.validate_email(email):
            raise ValueError("Invalid Email Format!")
        self.username = username
        self.email = email

    @staticmethod
    def validate_email(email):
        return re.match(r"[^@]+@[^@]+\.[^@]+", email)

# Real-Life Usage
try:
    user1 = User("alice", "alice@example.com")  # Valid email
    print("User registered successfully!")
except ValueError as e:
    print(e)

try:
    user2 = User("bob", "bob@invalid-email")  # Invalid email
except ValueError as e:
    print(e)  # Output: Invalid Email Format!
Python

Why use a static method?

  • It doesn’t need to modify or access any attributes (instance or class).
  • It’s a self-contained utility function inside the class.
  • Keeps email validation logic inside the User class, maintaining code organization.

All in one

class Employee:
    company_name = "TechCorp"  # Class variable shared by all instances
    employee_count = 0         # Class variable to track number of employees

    def __init__(self, name, salary):
        self.name = name               # Instance variable
        self.salary = salary           # Instance variable
        Employee.employee_count += 1   # Update class variable

    # Instance method: uses 'self', can access instance and class variables
    def show_details(self):
        print(f"Name: {self.name}")
        print(f"Salary: ${self.salary}")
        print(f"Company: {Employee.company_name}")  # Access class variable
        print()

    # Class method: uses 'cls', can access/modify class variables only
    @classmethod
    def update_company(cls, new_name):
        print(f"Changing company name from {cls.company_name} to {new_name}")
        cls.company_name = new_name

    # Static method: does not use 'self' or 'cls', utility method
    @staticmethod
    def is_valid_salary(salary):
        return salary > 0


# --- Using the class ---

# Check salary using static method (without creating object)
print("Is 5000 a valid salary?", Employee.is_valid_salary(5000))
print("Is -1000 a valid salary?", Employee.is_valid_salary(-1000))
print()

# Create objects (instances)
emp1 = Employee("Alice", 5000)
emp2 = Employee("Bob", 6000)

# Use instance method
emp1.show_details()
emp2.show_details()

# Use class method to update company name
Employee.update_company("InnoTech")

# Show updated class variable via instance method
emp1.show_details()
emp2.show_details()

# Show total number of employees (accessing class variable directly)
print(f"Total employees: {Employee.employee_count}")
Python

Output

Is 5000 a valid salary? True
Is -1000 a valid salary? False

Name: Alice
Salary: $5000
Company: TechCorp

Name: Bob
Salary: $6000
Company: TechCorp

Changing company name from TechCorp to InnoTech

Name: Alice
Salary: $5000
Company: InnoTech

Name: Bob
Salary: $6000
Company: InnoTech

Total employees: 2
Python

Parameter cls, self

cls in class Method

  • cls is a convention used to represent the class itself in class methods.
  • Just like self refers to the instance of a class, cls refers to the class when working with class methods.
  • It allows accessing and modifying class-level attributes.
  • This allows you to modify instance creation, such as implementing a singleton pattern or controlling subclass instantiation.

self in Instance Method

  • Instance methods operate on a specific instance of a class.
  • The first parameter, self, represents the instance itself, giving access to instance attributes and methods.
  • Without self, Python wouldn’t know which instance’s attributes or methods to modify.

No self or cls in Static Methods

  • Static methods do not operate on an instance or class; they are just functions inside a class.
  • They don’t have access to instance (self) or class (cls) attributes unless explicitly passed.
  • Defined using @staticmethod, they are useful for utility functions that logically belong to the class but don’t need access to the class or instance state.

Why cls? , why not use self in class method?

Because the instance doesn’t exist yet, but the class does.

__new__

  • __new__ is a special method that is called before __init__.
  • It is responsible for creating and returning a new instance of the class.
  • It’s a static method under the hood, and is rarely overridden unless you’re doing something special (like implementing singletons, immutability, or subclassing immutable types like int or str).

When is __new__ used?

  • When customizing object creation (before initialization).
  • When subclassing immutable types like str, int, tuple, etc.
  • In design patterns (like Singleton or Factory).

Flow of Object Creation

  • __new__ is called → it creates and returns a new object.
  • __init__ is called → it initializes that object.

Example: Basic

class Demo:
    def __new__(cls, *args, **kwargs):
        print("Inside __new__")
        instance = super().__new__(cls)
        return instance

    def __init__(self, value):
        print("Inside __init__")
        self.value = value

obj = Demo(42)

'''
Inside __new__
Inside __init__
'''
Python

Example: Customizing Object Creation

class LimitInstances:
    count = 0
    limit = 2

    def __new__(cls, *args, **kwargs):
        if cls.count >= cls.limit:
            print("Limit reached. No more instances allowed.")
            return None
        cls.count += 1
        return super().__new__(cls)

    def __init__(self, name):
        self.name = name
        print(f"Instance created: {self.name}")

a = LimitInstances("A")  # Allowed
b = LimitInstances("B")  # Allowed
c = LimitInstances("C")  # Blocked


'''
Instance created: A
Instance created: B
Limit reached. No more instances allowed.
'''
Python

Conclusion

Understanding these three types of methods in Python helps in writing cleaner and more efficient code. Instance methods are used for working with object attributes, class methods work with class attributes, and static methods provide utility functionality that doesn’t rely on instance or class attributes.

  • Use instance methods when working with object-specific data.
  • Use class methods when working with shared data across all instances.
  • Use static methods for utility functions that don’t depend on instance or class attributes.

Resource

1 thought on “Class Methods, Static Methods, and Instance Methods in Python”

Leave a Comment