
Python
Beyond instance methods, Python offers static methods, class methods, and sophisticated patterns for method decoration and control. Understanding these advanced method types enables you to write flexible, reusable code that scales to complex systems.
Static methods don't access `self` or class state. They're utility functions grouped with a class. Use `@staticmethod` decorator.
import math
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 circle_area(radius):
return math.pi * radius ** 2
# Call without creating instance
print(Calculator.add(5, 3)) # Output: 8
print(Calculator.circle_area(5)) # Output: 78.54
# Can still call from instance
calc = Calculator()
print(calc.add(10, 20)) # Output: 30Class methods receive the class as the first parameter (cls), not an instance. Use `@classmethod` decorator. Useful for factory methods and working with class state.
class Person:
population = 0
def __init__(self, name, age):
self.name = name
self.age = age
Person.population += 1
@classmethod
def from_birth_year(cls, name, birth_year):
"""Factory method using class method"""
age = 2026 - birth_year
return cls(name, age)
@classmethod
def get_population(cls):
"""Access class variable"""
return cls.population
@classmethod
def reset_population(cls):
"""Modify class variable"""
cls.population = 0
p1 = Person.from_birth_year("Alice", 1995)
print(f"{p1.name} is {p1.age}")
p2 = Person("Bob", 30)
print(f"Total people: {Person.get_population()}")Understanding when to use each method type is crucial for clean architecture.
class FileHandler:
supported_formats = ['.txt', '.json', '.csv']
def __init__(self, filename):
self.filename = filename
# Instance method - works with instance data
def read(self):
return f"Reading {self.filename}"
def write(self, content):
self.content = content
return f"Writing to {self.filename}"
# Class method - works with class data
@classmethod
def is_supported(cls, filename):
for fmt in cls.supported_formats:
if filename.endswith(fmt):
return True
return False
@classmethod
def add_format(cls, format_type):
cls.supported_formats.append(format_type)
# Static method - utility function
@staticmethod
def validate_filename(filename):
return len(filename) > 0 and '.' in filename
# Test different method types
print(FileHandler.validate_filename("test.txt")) # Static
print(FileHandler.is_supported("data.json")) # Class
FileHandler.add_format('.yaml')
handler = FileHandler("data.csv")
print(handler.read()) # Instance
handler.write("some data")Decorators enhance or modify method behavior without changing their implementation.
import functools
import time
def timing_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} took {elapsed:.4f} seconds")
return result
return wrapper
def logging_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
result = func(*args, **kwargs)
print(f"Result: {result}")
return result
return wrapper
class DataProcessor:
@timing_decorator
def process_large_file(self, data):
time.sleep(0.1) # Simulate work
return f"Processed {len(data)} items"
@logging_decorator
def analyze(self, data):
return sum(data) / len(data)
@logging_decorator
@timing_decorator
def complex_operation(self, data):
time.sleep(0.05)
return max(data)
processor = DataProcessor()
print(processor.process_large_file([1, 2, 3, 4, 5]))
print(processor.analyze([10, 20, 30]))
print(processor.complex_operation([5, 15, 10]))Use methods to enforce access control and maintain invariants.
class BankAccount:
def __init__(self, owner, balance):
self._owner = owner
self._balance = balance
self._transaction_limit = 1000
@property
def balance(self):
"""Read-only property"""
return self._balance
@property
def owner(self):
return self._owner
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit must be positive")
self._balance += amount
return self._balance
def withdraw(self, amount):
if amount <= 0:
raise ValueError("Withdrawal must be positive")
if amount > self._transaction_limit:
raise ValueError(f"Exceeds limit of ${self._transaction_limit}")
if amount > self._balance:
raise ValueError("Insufficient funds")
self._balance -= amount
return self._balance
account = BankAccount("Alice", 5000)
print(account.balance)
print(account.deposit(1000))
print(account.withdraw(500))
# Invalid operations are prevented
try:
account.withdraw(5000)
except ValueError as e:
print(f"Error: {e}")class APIClient:
base_url = "https://api.example.com"
timeout = 30
def __init__(self, api_key):
self.api_key = api_key
@staticmethod
def validate_api_key(key):
return len(key) >= 32 and key.isalnum()
@classmethod
def set_timeout(cls, seconds):
cls.timeout = seconds
@classmethod
def from_env(cls):
"""Factory method"""
import os
api_key = os.getenv("API_KEY")
return cls(api_key)
def get(self, endpoint):
if not self.validate_api_key(self.api_key):
raise ValueError("Invalid API key")
url = f"{self.base_url}/{endpoint}"
return f"GET {url} with timeout {self.timeout}s"
def post(self, endpoint, data):
if not self.validate_api_key(self.api_key):
raise ValueError("Invalid API key")
url = f"{self.base_url}/{endpoint}"
return f"POST {url} with data {data}"
client = APIClient.from_env()
print(client.get("users"))
print(client.post("users", {"name": "John"}))
APIClient.set_timeout(60)class Model:
_table = None
_instances = {}
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
@classmethod
def create(cls, **kwargs):
"""Factory method for creating instances"""
instance = cls(**kwargs)
if cls._table:
cls._instances[id(instance)] = instance
return instance
@classmethod
def all(cls):
"""Get all instances"""
return list(cls._instances.values())
@classmethod
def find_by_name(cls, name):
"""Query instances"""
return [inst for inst in cls._instances.values()
if hasattr(inst, 'name') and inst.name == name]
def save(self):
"""Instance method"""
self._instances[id(self)] = self
return f"Saved {self.__class__.__name__}"
@staticmethod
def migrate():
"""Static utility"""
return "Running migrations..."
class User(Model):
_table = "users"
user1 = User.create(name="Alice", email="alice@example.com")
user2 = User.create(name="Bob", email="bob@example.com")
print(User.find_by_name("Alice"))
print(User.migrate())
print(user1.save())| Concept | Remember |
|---|---|
| Instance Method | Access self, work with object state |
| Static Method | No access to self/cls, utility functions |
| Class Method | Access cls, work with class state |
| @staticmethod | Decorator for static methods |
| @classmethod | Decorator for class methods |
| Factory Method | Use classmethod to create instances |
| Decorators | Enhance methods without modifying them |
| Method Types | Choose based on what data you need |
Continue with advanced patterns in other OOP concepts.
Advanced: Instance Variables →
Ready to practice? Try challenges or explore more concepts
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward