A method is a function defined inside a class. It can read and change the object’s data. Methods are how an object does things, as opposed to just storing things.
Instance methods (the common kind)
You’ve seen these already:
class Counter:
def __init__(self) -> None:
self.count: int = 0
def increment(self) -> None:
self.count += 1
def value(self) -> int:
return self.count
c = Counter()
c.increment()
c.increment()
print(c.value()) # 2
Methods take self as their first parameter. self is the object the method was called on. Inside, you read and modify self.something.
Calling vs accessing
c.value # the method itself — <bound method ...>
c.value() # call the method — returns the value
Don’t forget the parentheses. A common bug:
if c.value: # always truthy — the method object is truthy
...
if c.value(): # calls it — returns the count
...
Static methods — functions that don’t need self
A static method is a function attached to the class but that doesn’t use self. Use @staticmethod:
class Math:
@staticmethod
def add(a: int, b: int) -> int:
return a + b
print(Math.add(2, 3)) # 5
It’s basically a regular function namespaced under the class. You can call it on the class or on any instance — both work. Use a static method when the function is logically related to the class but doesn’t touch any specific object’s state.
In practice, static methods are rare. A module-level function usually fits better.
Class methods — operate on the class, not an instance
A class method receives the class itself as its first argument (conventionally named cls). Use @classmethod:
class User:
def __init__(self, name: str, age: int) -> None:
self.name = name
self.age = age
@classmethod
def from_dict(cls, data: dict[str, str | int]) -> "User":
return cls(data["name"], data["age"])
record = {"name": "Manikandan", "age": 30}
u = User.from_dict(record)
print(u.name, u.age)
The pattern from_dict (or from_json, from_csv_row) is an alternative constructor — a different way to create an object. Class methods are the right tool for this.
cls lets the method work correctly when subclasses are involved — but we’ll save that detail for the inheritance lesson.
Dunder methods (special methods)
Python uses double-underscore methods (often called “dunder methods”) to hook into language features. You’ve already met __init__ and __repr__. A few more:
class Vector:
def __init__(self, x: float, y: float) -> None:
self.x = x
self.y = y
def __repr__(self) -> str:
return f"Vector({self.x}, {self.y})"
def __add__(self, other: "Vector") -> "Vector":
return Vector(self.x + other.x, self.y + other.y)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Vector):
return NotImplemented
return self.x == other.x and self.y == other.y
def __abs__(self) -> float:
return (self.x ** 2 + self.y ** 2) ** 0.5
a = Vector(1, 2)
b = Vector(3, 4)
print(a + b) # Vector(4, 6)
print(a == Vector(1, 2)) # True
print(abs(Vector(3, 4))) # 5.0
The dunder methods let your object behave like a built-in type:
__init__— construction__repr__/__str__— printing__eq__,__lt__,__gt__— comparison__add__,__sub__,__mul__— arithmetic__len__—len()__getitem__,__setitem__—obj[key]__iter__,__next__— iteration
You won’t define all of these in most classes. Define them when you genuinely want your object to act like a value (a number, a container, a record).
Method chaining
If a method returns self, you can chain calls:
class QueryBuilder:
def __init__(self) -> None:
self.parts: list[str] = []
def select(self, columns: str) -> "QueryBuilder":
self.parts.append(f"SELECT {columns}")
return self
def from_(self, table: str) -> "QueryBuilder":
self.parts.append(f"FROM {table}")
return self
def where(self, condition: str) -> "QueryBuilder":
self.parts.append(f"WHERE {condition}")
return self
def build(self) -> str:
return " ".join(self.parts)
query = QueryBuilder().select("name").from_("users").where("age > 18").build()
print(query)
# SELECT name FROM users WHERE age > 18
This is the pattern Pandas uses heavily — df.dropna().sort_values("age").head(10).
What’s next
You can give objects behaviour. Next, properties — methods that look like attributes.