Constructors and self
Problem
A €0 coffee
You create a product, just like in the last lesson, and fill in the fields line by line. You forgot one line:
coffee = Product()coffee.name = "Coffee"coffee.quantity = 2print(f"{coffee.name}: €{coffee.price * coffee.quantity}")Coffee: €0.0The coffee costs €0. Python does not complain: the price has a value, 0.0 from __init__. The more fields a class has, the easier it is to miss one. And a product without a price should not be able to exist at all.
The idea
Constructor: no object without this data
A class can say what it needs before you can create an object from it. That is what the constructor is for: a special method that runs on Product(...). In Python this is __init__, which you have already seen, except that now it takes parameters.
class Product: def __init__(self, name, price, quantity): self.name = name self.price = price self.quantity = quantity
coffee = Product("Coffee", 7.50, 2)print(f"{coffee.name}: €{coffee.price * coffee.quantity}")Coffee: €15.0- The constructor is called
__init__(two underscores before and two after), in every class. - Its first parameter is
self: the object being created. Python passes it for you. - The other parameters are the data a product cannot do without. You pass them in the parentheses:
Product("Coffee", 7.50, 2). - It returns nothing.
Product(...)returns the new object.
Now there is no way to forget the price. If you pass two arguments instead of three, the program stops right on that line:
coffee = Product("Coffee", 7.50)TypeError: Product.__init__() missing 1 required positional argument: 'quantity'class Product: def __init__(self, name, price, quantity): self.name = name self.price = price self.quantity = quantity
coffee = Product("Coffee", 7.50, 2)print(f"{coffee.name}: €{coffee.price * coffee.quantity}")Step by step, in words
- Product(...) makes a new object. It has no fields yet: __init__ will create them.
- __init__ runs. self is the new object, and the arguments go into the parameters.
- self.name = name: from the parameter into a new field of this object.
- The same for the price and the quantity.
- __init__ is done and the parameters disappear. coffee gets an arrow to the finished object.
- The object comes out of Product(...) already filled in, so the price is not 0.
The idea
self: the field of this object
Inside __init__ there are two things called name: the parameter and the field. name is the parameter. The field is self.name.
class Product: def __init__(self, name, price, quantity): self.name = name self.price = price self.quantity = quantityself is the object being created right now. self.name = name means "store the name parameter in the name field of this object".
In Python, self. is required. Without it, name = name is just a variable inside __init__, and it disappears as soon as __init__ ends. The name self is a convention, not a keyword, but everyone writes it that way.
Try it
Find the bug
AttributeError: 'Product' object has no attribute 'name'. Which line has the bug?Pick the line with the bug.
name = name stores the parameter in itself. The name field is never created, so tea.name does not exist. You need self.name = name. The error shows up only on the line that reads the name, far from the real cause.
The idea
What about Product() from the last lesson?
In the last lesson, __init__ had no parameters except self, so Product() worked. Now __init__ needs three arguments, and without them the program stops:
empty = Product()TypeError: Product.__init__() missing 3 required positional arguments: 'name', 'price', and 'quantity'That is the point: a product without a name and price can no longer be created.
More precisely, if you are curious
If a class has no __init__ at all, Product() still works: Python creates an object with no fields at all. That is why fields in Python are always created in __init__.
The idea
A default quantity
Most products in the cart come one at a time. Typing 1 every time gets tedious.
In Python a class has one __init__. Instead of a second constructor, the parameter gets a default value: if you do not pass a quantity, it is 1.
class Product: def __init__(self, name, price, quantity=1): self.name = name self.price = price self.quantity = quantityquantity=1 (no spaces around =) means "if no quantity is passed, use 1". Parameters with a default value come last. If you put a parameter without a default after quantity=1, Python will not run the file:
SyntaxError: parameter without a default follows parameter with a defaultMore precisely, if you are curious
A second __init__ in the class does not make a second constructor. It just replaces the first one, with no warning, and Product("Bread", 1.20) stops with:
TypeError: Product.__init__() missing 1 required positional argument: 'quantity'That is why Python has only one constructor. The upside: if you add a price check tomorrow, it is in one place.
Try it
Which constructor?
What will the program print?
class Product: def __init__(self, name, price, quantity=1): self.name = name self.price = price self.quantity = quantity
bread = Product("Bread", 1.20)milk = Product("Milk", 2.10, 3)print(bread.quantity, milk.quantity)Product("Bread", 1.20) has no quantity, so quantity takes the default value 1. For the milk, the quantity is passed: 3.Try it
What is the constructor called?
What goes in the blank?
class Book:
def (self, title, author):
self.title = title
self.author = author__init__: that is the constructor's name in every class, with two underscores on each side.Exercise
Objects created whole
Solve these in your editor. Every class gets a constructor with parameters for all of its fields.
1. Person. A Person class with a name and an age. Create two people and print their details.
Maria, 34 yearsPeter, 19 years2. Animal. An Animal class with a species and an age. Create a 3-year-old cat and a 7-year-old dog.
Species: cat, age: 3Species: dog, age: 73. Dance move. A DanceMove class with a name and a duration in seconds. In the "Behavior" lesson, the move will learn to "perform" itself.
moonwalk: 5 sec.More practice
- A book with a constructor. Rewrite
Bookfrom the last lesson with a__init__(self, title, author)constructor. How many lines did you save in the code under the class? -
A product with a default quantity.
Productwithquantity=1, as in the lesson. Make a list[Product("Bread", 1.20, 2), Product("Coffee", 7.50)]and print the name and quantity of each: "Bread x2", "Coffee x1". - Booking. A
Bookingclass with the guest's name, the number of nights, and the price per night. Print what the stay costs: for 3 nights at €85, that is €255.
Test