The constructor and self
A constructor sets up each new object as it is made, so that every object gets the same attributes. In Python, the constructor is a method with the special name __init__ (two underscores on each side of init), written inside the class:
class Planet:
def __init__(self, name, moons):
self.name = name
self.moons = moons
home = Planet("Earth", 1)
far = Planet("Neptune", 16)
print(home.name, home.moons)
print(far.name, far.moons)
Earth 1
Neptune 16A function defined inside a class is a method, and __init__ is the one that Python calls by itself whenever a new object is made.
self
The first parameter of __init__ is always self: the object being set up. You never pass it yourself, because Python does that. So __init__ here has three parameters, but you call Planet with two arguments.
Follow one call, Planet("Earth", 1), from start to end:
- Python makes a new, empty
Planetobject. - It calls
__init__. Inside the call there are three local variables, the parameters:selfrefers to the new object,nameis"Earth"andmoonsis1. self.name = namereads the local variablenameand stores its value in the object, under the attribute namename. The next line does the same formoons.__init__ends, and its local variables end with it, as in any function. What was stored in the object stays there: the object now hasname"Earth"andmoons1.- The finished object is the value of
Planet("Earth", 1), and it is stored inhome, sohome.nameis"Earth".
So in self.name = name, the name on the right is the parameter and the name after self. is the attribute. They only share the spelling. A constructor def __init__(self, planet_name, moons): with self.name = planet_name would make exactly the same objects, though it is more to read.
Forgetting self. is a common mistake. Then name = name only assigns the local variable to itself, and the object gets nothing:
class Planet:
def __init__(self, name, moons):
name = name
self.moons = moons
home = Planet("Earth", 1)
print(home.moons)
print(home.name)
1Traceback (most recent call last):
File "main.py", line 9, in <module>
print(home.name)
^^^^^^^^^
AttributeError: 'Planet' object has no attribute 'name'The right arguments
The constructor's parameters decide what you must give when you make an object. Leave one out, and Python names the missing one:
class Planet:
def __init__(self, name, moons):
self.name = name
self.moons = moons
far = Planet("Neptune")
Traceback (most recent call last):
File "main.py", line 7, in <module>
far = Planet("Neptune")
TypeError: Planet.__init__() missing 1 required positional argument: 'moons'If the error says Planet() takes no arguments instead, Python didn't find a constructor at all: check the spelling of __init__, with two underscores on each side.
As in functions, type hints are welcome in a constructor: def __init__(self, name: str, moons: int):. They don't change what the code does.