Why a constructor
Without a constructor, you create an object and then fill it in line by line:
dog = Dog()
dog.name = "Rex"
dog.age = 4
That works, but it is wordy and easy to forget a line. If one dog never gets its age, the error shows up much later, when something reads it. Python's constructor, the __init__ method, sets the attributes in the same step that creates the object.
Defining __init__
Two things are special about it:
- The name is
__init__, with two underscores on each side. Python programmers call names like this "dunders", short for double underscores. Python calls the method automatically; you do not call it yourself. - The first parameter is
self. It is the object being set up, and Python passes it in for you.
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
The line self.name = name reads as "store the parameter name as an attribute called name on this object". The two names are unrelated: the left one is an attribute of the object, the right one is the local parameter. They are often the same word, which is a convention and not a requirement.
Calling the constructor
You pass the arguments when you create the object, after the class name, and leave self out:
rex = Dog("Rex", 4)
luna = Dog("Luna", 7)
print(rex.name, rex.age)
print(luna.name, luna.age)
Rex 4
Luna 7
Python does the following for Dog("Rex", 4): it creates an empty Dog object, then calls __init__ with that object as self, followed by "Rex" and 4. By the time the line finishes, the attributes are in place.
The lesson's exercise
The starter code has a Dog class with only pass in it, and two print lines at the bottom that read name and age from rex and luna. The task is to give Dog a constructor and then create the two dogs.
- Replace
passwith the constructor. Writedef __init__(self, name, age):inside the class, indented one level. - Assign the attributes. In the body, write
self.name = nameandself.age = age, indented one level further. - Create the dogs. Below the class, write
rex = Dog("Rex", 4)andluna = Dog("Luna", 7).
The final code builds each message by joining strings. The age is a number, so it goes through str() first:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
rex = Dog("Rex", 4)
luna = Dog("Luna", 7)
print(rex.name + " is " + str(rex.age))
print(luna.name + " is " + str(luna.age))
Rex is 4
Luna is 7
What else a constructor can do
The constructor is ordinary code, so it can do more than copy parameters. It can check its inputs, tidy them up, or create attributes that no argument supplies:
class Dog:
def __init__(self, name, age):
if age < 0:
raise ValueError("age cannot be negative")
self.name = name.strip().title()
self.age = age
self.tricks = []
d = Dog(" rex ", 4)
print(d.name, d.tricks)
Rex []
Here the name is cleaned up, a bad age is rejected before the object is finished, and every dog starts with its own empty tricks list. The lesson's exercise only needs the plain assignments, but this is why a constructor is a better place for setup than lines scattered after the call.
Gotchas
Every call must supply the arguments
Once __init__ asks for name and age, a call without them fails:
Dog("Rex")
TypeError: Dog.__init__() missing 1 required positional argument: 'age'
If you want an argument to be optional, give the parameter a default value, as in def __init__(self, name, age=1):. Then Dog("Rex") works and the age is 1.
Forgetting self.
This version looks plausible but stores nothing:
class Bad:
def __init__(self, name):
name = name
The assignment only rebinds the local parameter. The object ends up with no attribute, and reading .name later raises an AttributeError.
Returning a value
The constructor must not return anything other than None. A return 5 inside __init__ raises a TypeError when the object is created. Its job is to set up the object, not to produce a result.
Misspelling the name
Python only calls a method named exactly __init__. A method called _init_ or init is just an ordinary method, and the object is created without any setup.
Key takeaways
__init__is Python's constructor. It runs automatically when you create an object.- Its first parameter is
self, the new object. You do not pass it when calling the class. - Assign attributes with
self.name = name, so they belong to the object. - The arguments in
Dog("Rex", 4)go to the parameters afterself.