Skip to content
wannacode

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 = 2
print(f"{coffee.name}: €{coffee.price * coffee.quantity}")
Output
Coffee: €0.0

The 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.

shop.py
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}")
Output
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)
Error
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
  1. Product(...) makes a new object. It has no fields yet: __init__ will create them.
  2. __init__ runs. self is the new object, and the arguments go into the parameters.
  3. self.name = name: from the parameter into a new field of this object.
  4. The same for the price and the quantity.
  5. __init__ is done and the parameters disappear. coffee gets an arrow to the finished object.
  6. 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 = quantity

self 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

The program should print "Tea: €3.2". Instead, it stops with AttributeError: 'Product' object has no attribute 'name'. Which line has the bug?

Pick the line with the bug.

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()
Error
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 = quantity

quantity=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:

Error
SyntaxError: parameter without a default follows parameter with a default
More 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:

Error
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)
Answer

Try it

What is the constructor called?

What goes in the blank?

class Book:
    def (self, title, author):
        self.title = title
        self.author = author

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.

Output
Maria, 34 years
Peter, 19 years

2. Animal. An Animal class with a species and an age. Create a 3-year-old cat and a 7-year-old dog.

Output
Species: cat, age: 3
Species: dog, age: 7

3. Dance move. A DanceMove class with a name and a duration in seconds. In the "Behavior" lesson, the move will learn to "perform" itself.

Output
moonwalk: 5 sec.

More practice

  • A book with a constructor. Rewrite Book from 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. Product with quantity=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 Booking class 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

Check yourself

1. When does __init__ run?
2. What is the constructor called in Python?
3. The class has only def __init__(self, name, price). What happens with Product()?
4. The __init__ says self.name = name. What is self.name?
5. How does the class give a quantity of 1 when none is passed at creation?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·