Web Analytics

Methods

Intermediate ~30 min read

Methods are functions defined inside a class that operate on objects. Python has three types: instance methods (most common, use self), class methods (use @classmethod and cls), and static methods (use @staticmethod, no special first parameter). Each serves a different purpose!

Instance Methods

Instance methods are the most common type. They take self as the first parameter, which refers to the instance calling the method. This lets them access and modify instance attributes. When you call obj.method(), Python automatically passes obj as self.

Output
Click Run to execute your code
Instance Methods:
def method(self): - First parameter is always self
obj.method() - Python passes obj as self automatically
self.attr - Access instance attributes
self.other_method() - Call other instance methods

Use for: Operations that need instance data or modify instance state.

Class Methods

Class methods use the @classmethod decorator and receive the class (not instance) as the first parameter, conventionally called cls. They're perfect for alternative constructors (factory methods) and operations on class-level data. They work with inheritance too!

Output
Click Run to execute your code
Class Methods - When to Use:
@classmethod + cls parameter

- Alternative constructors: from_string(), from_dict()
- Factory methods that create instances
- Access/modify class attributes
- Methods that should work with inheritance (cls is actual class)

Static Methods

Static methods use the @staticmethod decorator and don't receive self or cls. They're essentially regular functions that live in a class's namespace. Use them for utility functions that are logically related to the class but don't need instance or class data.

Output
Click Run to execute your code
Static Methods - When to Use:
@staticmethod - No self or cls parameter

- Utility functions related to the class
- Validation helpers
- Conversion functions
- When you don't need instance or class data
- Namespace organization (group related functions)

Method Chaining

Method chaining (fluent interface) lets you call multiple methods in sequence: obj.method1().method2().method3(). The trick is returning self from each method. This pattern creates readable, expressive code for builders and queries.

Output
Click Run to execute your code
Method Chaining Tips:
- Return self from methods you want to chain
- Final method often returns a result (not self): .build(), .execute()
- Use parentheses for multi-line chains for readability
- Don't overuse - sometimes explicit steps are clearer

Common Mistakes

1. Forgetting self in instance methods

# Wrong - missing self parameter!
class Dog:
    def bark():  # Missing self!
        print("Woof!")

dog = Dog()
dog.bark()  # TypeError: bark() takes 0 arguments but 1 was given

# Correct - include self
class Dog:
    def bark(self):
        print("Woof!")

2. Using self in static method

# Wrong - static methods don't have self!
class Calculator:
    @staticmethod
    def add(self, a, b):  # self doesn't belong here!
        return a + b

# Correct - no self in static method
class Calculator:
    @staticmethod
    def add(a, b):
        return a + b

3. Using cls with instance method

# Wrong - instance methods use self, not cls
class Person:
    def greet(cls):  # Should be self!
        print(f"Hello, {cls.name}")  # Confusing!

# Correct - use self for instance methods
class Person:
    def greet(self):
        print(f"Hello, {self.name}")

# Use cls only with @classmethod
class Person:
    @classmethod
    def create(cls, name):  # cls is correct here
        return cls(name)

4. Forgetting return self for chaining

# Wrong - can't chain without return self
class Builder:
    def set_name(self, name):
        self.name = name
        # Missing return self!

    def set_age(self, age):
        self.age = age

b = Builder()
b.set_name("Alice").set_age(30)  # AttributeError: 'NoneType'

# Correct - return self for chaining
class Builder:
    def set_name(self, name):
        self.name = name
        return self

    def set_age(self, age):
        self.age = age
        return self

5. Wrong method type for the job

# Wrong - using static when you need class
class Counter:
    count = 0

    @staticmethod
    def increment():
        Counter.count += 1  # Hardcoded class name!

# Better - use classmethod for class operations
class Counter:
    count = 0

    @classmethod
    def increment(cls):
        cls.count += 1  # Works with inheritance!

# Wrong - using instance method for utility
class Math:
    def add(self, a, b):  # self is never used!
        return a + b

# Better - use staticmethod for utilities
class Math:
    @staticmethod
    def add(a, b):
        return a + b

Exercise: Shopping Cart

Task: Create a ShoppingCart class with different method types.

Requirements:

  • Instance method: add_item(name, price) - adds item and returns self for chaining
  • Instance method: total() - returns total price
  • Class method: from_list(items) - creates cart from list of (name, price) tuples
  • Static method: format_price(amount) - formats number as "$X.XX"
Output
Click Run to execute your code
Show Solution
class ShoppingCart:
    """Shopping cart with different method types."""

    def __init__(self):
        self.items = []

    def add_item(self, name, price):
        """Instance method - add item and return self for chaining."""
        self.items.append({'name': name, 'price': price})
        return self

    def total(self):
        """Instance method - calculate total price."""
        return sum(item['price'] for item in self.items)

    def display(self):
        """Instance method - show cart contents."""
        print("Shopping Cart:")
        for item in self.items:
            print(f"  - {item['name']}: {self.format_price(item['price'])}")
        print(f"  Total: {self.format_price(self.total())}")

    @classmethod
    def from_list(cls, items):
        """Class method - create cart from list of (name, price) tuples."""
        cart = cls()
        for name, price in items:
            cart.add_item(name, price)
        return cart

    @staticmethod
    def format_price(amount):
        """Static method - format price as currency."""
        return f"${amount:.2f}"


# Test instance methods with chaining
cart1 = ShoppingCart()
cart1.add_item("Apple", 1.50).add_item("Banana", 0.75).add_item("Orange", 2.00)
cart1.display()

print()

# Test class method (alternative constructor)
items_list = [("Milk", 3.50), ("Bread", 2.25), ("Eggs", 4.00)]
cart2 = ShoppingCart.from_list(items_list)
cart2.display()

print()

# Test static method
print(f"Formatted price: {ShoppingCart.format_price(99.999)}")

Summary

  • Instance methods: def method(self) - access instance data
  • Class methods: @classmethod + cls - access class, alternative constructors
  • Static methods: @staticmethod - no self/cls, utility functions
  • self: Passed automatically when calling obj.method()
  • cls: Receives the class itself, works with inheritance
  • Method chaining: Return self to enable .method1().method2()
  • Choose wisely: Instance for data, class for factories, static for utilities

What's Next?

Now you know how to create classes with attributes and methods. Next, we'll learn about inheritance - how to create new classes based on existing ones. You'll learn to extend functionality, override methods, and build class hierarchies!