Python Mastery: Complete Beginner to Professional
HomeInsightsCoursesPythonClass vs Static Methods

Method Types: Instance, Class, & Static

Mastering the three flavors of Python methods: From Pizza Factories to Math Utilities.

1. The Big Idea (ELI5)

👶 Explain Like I'm 10: The Pizza Place

Imagine a Pizza Restaurant. There are three types of jobs:

  • Instance Method (The Chef): The Chef (`self`) makes a specific pizza. He touches the dough, adds the cheese. He needs to know about this specific pizza to do his job.
  • Class Method (The Manager): The Manager (`cls`) doesn't make pizzas. She hires new Chefs. She creates the team. She cares about the "Pizza Place" as a whole, not just one pepperoni slice.
  • Static Method (The Janitor): The Janitor cleans the floor. He doesn't touch the pizzas (`self`) and he doesn't hire people (`cls`). He is just there to help, doing his own thing independently.

This distinction is critical because choosing the wrong one can make your code harder to test and harder to extend.

2. The Three Flavors of Methods

In Python, not all methods are created equal. When you write a function inside a class, you have three choices:

TypeDecoratorFirst ArgumentRole
Instance(None)`self`The Chef (Works on one object)
Class`@classmethod``cls`The Manager (Works on the Factory)
Static`@staticmethod`(None)The Janitor (Works alone)

Why separation of duties matters

You might be tempted to just use Instance methods for everything. While possible, it leads to messy code. Separating concerns (Creation vs Action vs Utility) makes your code self-documenting. When a developer sees `@classmethod`, they immediately know "Ah, this creates an object". When they see `@staticmethod`, they know "Safe to ignore, this doesn't touch my object state".

3. Instance Methods (The Chef)

These are the standard. They take `self` because they need to know WHICH object they are modifying.

PYTHON
class PizzaChef:
    def __init__(self, name):
        self.name = name
        self.pizzas_made = 0

    # Instance Method: Needs 'self' to update 'pizzas_made'
    def make_pizza(self):
        self.pizzas_made += 1
        print(f"Chef {self.name} made a pizza! Total: {self.pizzas_made}")

mario = PizzaChef("Mario")
luigi = PizzaChef("Luigi")

mario.make_pizza() # Chef Mario made a pizza! Total: 1
luigi.make_pizza() # Chef Luigi made a pizza! Total: 1

4. Class Methods (The Manager)

Class methods don't care about individual chefs. They care about the Class itself. We mostly use them as Alternative Constructors (Factories) to create new objects.

PYTHON
class Pizza:
    def __init__(self, ingredients):
        self.ingredients = ingredients

    def __repr__(self):
        return f"Pizza({self.ingredients})"

    # Factory 1: The Margherita Special
    @classmethod
    def margherita(cls):
        # 'cls' is the Pizza class!
        return cls(['mozzarella', 'tomatoes', 'basil'])

    # Factory 2: The Pepperoni Special
    @classmethod
    def pepperoni(cls):
        return cls(['mozzarella', 'tomatoes', 'pepperoni'])
    
    # Factory 3: From CSV String
    @classmethod
    def from_string(cls, str_data):
        # "cheese,ham" -> ['cheese', 'ham']
        ingredients = str_data.split(',')
        return cls(ingredients)

# Usage
# We don't need to manually list ingredients. The Factory does it.
lunch = Pizza.margherita()
dinner = Pizza.from_string("cheese,ham")

print(lunch)  # Pizza(['mozzarella', 'tomatoes', 'basil'])

Why `cls`? If we make a new class `class DeepDish(Pizza)`, `cls` will automatically become `DeepDish`. So `DeepDish.margherita()` creates a Deep Dish pizza! Magic!

This is dynamic. If we had just hardcoded `return Pizza(...)`, subclassing would break because `DeepDish.margherita()` would still return a standard `Pizza`. Always use `cls` in factories to support inheritance.

5. Static Methods (The Janitor)

Static methods are just regular functions that live inside a class because it "looks nice" (organization). They cannot touch `self` or `cls`.

PYTHON
class MathUtils:
    
    @staticmethod
    def add(a, b):
        return a + b

    @staticmethod
    def is_positive(number):
        return number > 0

# Usage
# No object needed! Just call the class.
print(MathUtils.add(5, 10)) # 15

Design Choice: You might ask, "Why not just write a global function?" You can! But putting it inside the class keeps your code organized (Namespacing). `MathUtils.add` is cleaner than a random `add_numbers` function floating in your file.

6. Deep Dive: Bound vs Unbound Methods

What actually happens when you access `mario.make_pizza`? It's not just a simple function call. Python performs a dynamic binding process at runtime.

PYTHON
class A:
    def foo(self):
        print("Foo")

a = A()
print(a.foo) 
# Output: <bound method A.foo of <__main__.A object at ...>>

Python creates a tiny wrapper called a Bound Method. It glues the object `a` to the function `foo` to create a partial function. So when you call `a.foo()`, Python secretly runs `A.foo(a)`. **Why does this matter?** Every time you access `a.foo`, Python creates a NEW method object in memory. If you do this in a tight loop millions of times, it can be slow. This is why for high-performance code, we sometimes assign the method to a variable first (`local_foo = a.foo`) outside the loop.

Pro Tip: You can inspect this! `print(a.foo.__self__)` will show you the object `a` that is stuck to the method!

If you access it via the Class `A.foo`, it is an Unbound Method (or just a Function in Python 3).

7. Summary: The Decision Matrix

  • Does it need to access `self.variable`? -> Instance Method.
  • Does it need to create a new object instance? -> Class Method.
  • Does it generally relate to the class but touches no variables? -> Static Method.

8. Extended Technical Reference

Java `static` vs Python `@staticmethod`

In Java, `static` is used for global constants and utility methods. Python is similar, but there is a nuance:

  • Java: Static methods are purely class-level. They cannot be overridden in a polymorphic way easily.
  • Python: Static methods are just functions in a namespace. But Class Methods (`@classmethod`) ARE polymorphic because they receive `cls`. This is why Python prefers Class Methods for Factories.

Deep Dive: How Decorators Work

`@staticmethod` and `@classmethod` are actually Descriptors. When you access `obj.method`, the descriptor magic determines whether to pass `self`, `cls`, or nothing.

PYTHON
# What Python actually does:
# MyClass.my_method(obj) 
# is effectively:
# MyClass.__dict__['my_method'].__get__(obj, MyClass)

Which one is faster?

Technically, `@staticmethod` is slightly faster than an Instance Method because Python doesn't need to create a partially bound function (the "Bound Method" object). However, the difference is measured in nanoseconds. Always optimize for readability first.

What's Next?

Congratulations! You have completed the extended Object Oriented Programming module. You have learned about Robot Factories (Classes), Royal Families (Inheritance), Video Game Consoles (Pillars), Magic Spells (Dunder), and Pizza Places (Methods).

Next, we will look at Encapsulation & @property. We will learn how to protect our data without writing Java-style getters and setters.