Нашли ошибку?
Скачать чистый
урок 4 из 6≈ 20 минупражнения: 0 из 4

__init__ и self

Метод __init__ заполняет атрибуты нового экземпляра сразу при создании, а self — это сам этот экземпляр. Параметры, значения по умолчанию и забытый self.

Python запустится при первом выполнении

В прошлом уроке атрибуты записывались снаружи, по одному, и их было легко забыть. Правильное место для них — внутри класса, в специальном методе __init__.

Метод __init__

Функция, объявленная внутри класса, называется методом. У метода с именем __init__ особая роль: Python вызывает его сам, сразу после создания экземпляра. В __init__ экземпляр заполняют атрибутами:

[ ]Product с __init__
class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price


latte = Product("Латте", 220)
tea = Product("Чай", 120)
print(latte.name, latte.price)
print(tea.name, tea.price)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
Латте 220
Чай 120

Разберём по шагам, что делает Product("Латте", 220):

  1. Python создаёт новый пустой экземпляр Product.
  2. Вызывает __init__, передавая этот экземпляр первым аргументом, а "Латте" и 220 — следом. Первый параметр метода по соглашению называют self — «сам экземпляр».
  3. Строки self.name = name записывают атрибуты в этот экземпляр — так же, как cup.name = … снаружи.
  4. Готовый экземпляр возвращается и попадает в переменную.

Порядок легко увидеть, если напечатать что-нибудь внутри __init__:

[ ]Когда вызывается __init__
class Cup:
    def __init__(self, volume):
        print(f"__init__: заполняю экземпляр, volume = {volume}")
        self.volume = volume


print("до вызова Cup")
big = Cup(400)
print("после вызова Cup:", big.volume)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
до вызова Cup
__init__: заполняю экземпляр, volume = 400
после вызова Cup: 400

Метод __init__ называют инициализатором (initializer): он не создаёт объект — объект к этому моменту уже есть, — а заполняет его. Имена с двумя подчёркиваниями с обеих сторон Python зарезервировал для таких особых методов; их будет много, и у них есть общее название — магические методы (special methods; их ещё называют dunder — от double underscore). Подробно о них — в модуле 4.

Теперь забыть атрибут не получится: аргументы __init__ обязательны, и без них экземпляр не создастся:

[ ]Забыли аргументошибка: TypeError
Product("Чай")
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
TypeError: Product.__init__() missing 1 required positional argument: 'price'
[ ]Упражнение 1Напиток с __init__ решено

Допишите класс Drink: метод __init__(self, name, price) должен записывать в экземпляр атрибуты name и price.

class Drink:
    def __init__(self, name, price):
        ...  # запишите атрибуты name и price

Забытый self.

[ ]Атрибут без self.ошибка: AttributeError
class Bun:
    def __init__(self, name):
        name = name  # забыли self.


bun = Bun("Круассан")
print(bun.name)
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
AttributeError: 'Bun' object has no attribute 'name'
Вопрос

Сколько раз выполнится __init__ в этом коде?

a = Cup()
b = Cup()
c = a

Значения по умолчанию

Параметры __init__ — обычные параметры функции, и у них могут быть значения по умолчанию. Тогда аргумент можно не передавать:

[ ]Объём по умолчанию
class Product:
    def __init__(self, name, price, volume=250):
        self.name = name
        self.price = price
        self.volume = volume


print(Product("Капучино", 220).volume)
print(Product("Капучино", 260, 400).volume)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
250
400
[ ]Упражнение 2Размер по умолчанию решено

Объявите класс Drink заново, с тремя атрибутами: name, price и size. Размер по умолчанию — "M": Drink("Чай", 120) создаёт средний чай, а Drink("Чай", 150, "L") — большой.

class Drink:
    def __init__(self, name, price):  # добавьте параметр size
        ...

Атрибуты не только из аргументов

В __init__ можно записать и атрибут, которого нет среди параметров, — начальное значение, одинаковое для всех новых экземпляров, или значение, вычисленное из аргументов:

[ ]Начальное и вычисленное значение
class Pastry:
    def __init__(self, name, price, weight):
        self.name = name
        self.price = price
        self.weight = weight
        self.per_100g = round(price / weight * 100)  # вычислено из аргументов
        self.sold = 0  # начальное значение, одинаковое для всех


croissant = Pastry("Круассан", 140, 70)
print(croissant.per_100g, croissant.sold)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
200 0
[ ]Упражнение 3Новый покупатель решено

Объявите класс Customer: Customer("Анна", "+7 900 111-22-33") создаёт покупателя с атрибутами name и phone из аргументов и points — баллами лояльности. У нового покупателя их 0, и передавать их при создании не нужно.

class Customer:
    def __init__(self, name, phone):
        ...

Много экземпляров

Экземпляры удобно создавать в цикле: класс вызывается с разными аргументами, а объекты складываются в список.

[ ]Упражнение 4Меню из списка решено

В data — пары «название, цена». Создайте список menu из экземпляров Drink (из упражнения про размер) по этим данным — в том же порядке, размер у всех по умолчанию.

data = [("Эспрессо", 150), ("Капучино", 220), ("Раф", 260)]
menu = ...

Нашли ошибку?