Skip to content

Classes and Inheritance

The class keyword defines a new type. The body contains methods (functions defined inside a class) and optionally class attributes (shared by all instances).

class Dog:
species: str = "Canis lupus familiaris" # class attribute
def __init__(self, name: str, age: int) -> None:
self.name = name # instance attribute
self.age = age # instance attribute
def bark(self) -> str:
return f"{self.name} says woof!"

Every instance method receives the instance as its first argument, conventionally named self. Python passes it automatically; you never pass it yourself:

rex = Dog("Rex", 3)
rex.bark() # Python calls Dog.bark(rex) under the hood

self is not a keyword — you could name it anything — but self is the universal Python convention and deviating from it confuses every reader and every tool.

Instance attributeClass attribute
Where definedInside __init__, on selfDirectly in the class body
Where storedOn each individual objectOn the class itself
Accessobj.attrClassName.attr or obj.attr (fallback)

Mutating a class attribute through an instance creates a shadow instance attribute and does not change the class attribute for other instances. Use class attributes only for constants or shared state that truly belongs to the class.

A subclass inherits all methods from its parent. Use super() to call the parent’s method — most commonly super().__init__() to initialise the parent’s state.

class Animal:
def __init__(self, name: str, sound: str) -> None:
self.name = name
self.sound = sound
def speak(self) -> str:
return f"{self.name} says {self.sound}"
class Dog(Animal):
def __init__(self, name: str) -> None:
super().__init__(name, "woof") # delegate to Animal.__init__
def fetch(self, item: str) -> str:
return f"{self.name} fetches the {item}!"

super() without arguments works in Python 3 — no need to pass the class or instance explicitly.

class Animal:
kingdom: str = "Animalia"
def __init__(self, name: str, sound: str) -> None:
self.name = name
self.sound = sound
def speak(self) -> str:
return f"{self.name} says {self.sound}"
class Dog(Animal):
def __init__(self, name: str) -> None:
super().__init__(name, "woof")
def fetch(self, item: str) -> str:
return f"{self.name} fetches the {item}!"
dog = Dog("Rex")
print(dog.speak())
print(dog.fetch("ball"))
print(Dog.kingdom)
print(isinstance(dog, Animal))
What is the purpose of `__init__` in a Python class?
You define `species = 'Canis'` directly in the class body. What kind of attribute is it?
Inside an instance method, what does `self` refer to?
What does `super().__init__(name, sound)` do inside a subclass?