Template and instance
class Dog:
def __init__(self, name, age):
self.name = name
Dog describes what a dog is. Dog("rex", 3) builds one. Build two and they are independent: changing a.age leaves b.age alone, because each instance has its own attributes.
What __init__ does
__init__ runs immediately after the instance is created, and its job is to set up that instance's data. It is not a constructor in the C++ sense — the object already exists by the time it runs — but in practice it is where you put everything the object needs to start life.
The double underscores mark it as a name Python itself calls. You almost never call __init__ directly.
self is not magic
self is the instance, handed to the method as its first argument. Python does this for you: a.speak() is Dog.speak(a), and the page prints both to show they are the same call.
The name self is convention rather than syntax — the first parameter could be called anything — but every Python programmer expects self, and using something else will read as a mistake.
Every method that touches instance data needs it, and every attribute belonging to the instance is reached through it. Forgetting self. inside a method is the most common early error: you get a local variable that vanishes when the method returns.
Class attributes are shared
class Counter:
total = 0 # one, for everybody
def __init__(self):
self.count = 0 # one per instance
self.count belongs to the object. Counter.total belongs to the class and every instance sees the same one. This is occasionally what you want — a registry, a shared cache, a constant — and is a bug the rest of the time, in the same family as the mutable default argument.
__repr__ earns its keep immediately
By default, printing an object gives you something like <__main__.Point object at 0x104...>, which tells you nothing. Define __repr__ and you decide:
def __repr__(self):
return f"Point({self.x}, {self.y})"
It costs two lines and pays for itself the first time you print a list of them.
When to write one
Not for everything. If you have a function and some data it operates on, and they keep travelling together — passed to the same functions, returned in pairs — a class makes that relationship explicit. If you just need to return two values, a tuple is lighter and clearer.