Ojasa Mirai

Ojasa Mirai

Python

Loading...

Learning Level

🟢 Beginner🔵 Advanced
Classes & ObjectsMethods & SelfInstance VariablesClass VariablesConstructors & InitializationInheritance BasicsPolymorphismEncapsulationMagic Methods & Dunder
Python/Oop/Methods And Self

🎬 Methods & Self — Advanced Method Types and Patterns

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

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: 30

🏛️ Class Methods

Class 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()}")

📊 Comparing Method Types

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")

🔄 Method Decoration Patterns

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]))

🛡️ Access Control with Methods

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}")

📚 Real-World Examples

API Client with Method Patterns

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)

Database ORM Pattern

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())

✅ Key Takeaways

ConceptRemember
Instance MethodAccess self, work with object state
Static MethodNo access to self/cls, utility functions
Class MethodAccess cls, work with class state
@staticmethodDecorator for static methods
@classmethodDecorator for class methods
Factory MethodUse classmethod to create instances
DecoratorsEnhance methods without modifying them
Method TypesChoose based on what data you need

🔗 What's Next?

Continue with advanced patterns in other OOP concepts.

Advanced: Instance Variables →


Ready to practice? Try challenges or explore more concepts


Resources

Python Docs

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

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn