Methods
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.
Click Run to execute your code
def method(self): - First parameter is always selfobj.method() - Python passes obj as self automaticallyself.attr - Access instance attributesself.other_method() - Call other instance methodsUse 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!
Click Run to execute your code
@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.
Click Run to execute your code
@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.
Click Run to execute your code
- 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"
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
selfto 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!
Enjoying these tutorials?