В прошлом уроке атрибуты записывались снаружи, по одному, и их было легко забыть. Правильное место для
них — внутри класса, в специальном методе __init__.
Метод __init__
Функция, объявленная внутри класса, называется методом. У метода с именем __init__ особая роль:
Python вызывает его сам, сразу после создания экземпляра. В __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):
- Python создаёт новый пустой экземпляр
Product. - Вызывает
__init__, передавая этот экземпляр первым аргументом, а"Латте"и220— следом. Первый параметр метода по соглашению называютself— «сам экземпляр». - Строки
self.name = nameзаписывают атрибуты в этот экземпляр — так же, какcup.name = …снаружи. - Готовый экземпляр возвращается и попадает в переменную.
Порядок легко увидеть, если напечатать что-нибудь внутри __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__ обязательны, и без них экземпляр не создастся:
Product("Чай")TypeError: Product.__init__() missing 1 required positional argument: 'price'
Допишите класс Drink: метод __init__(self, name, price) должен записывать в экземпляр атрибуты name
и price.
self.name = name и self.price = price.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Drink:
def __init__(self, name, price):
... # запишите атрибуты name и priceУпражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Drink:
def __init__(self, name, price):
self.name = name
self.price = priceЗабытый self.
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__ вызывается при каждом создании экземпляра, то есть при каждом вызове Cup(). Строка c = a нового экземпляра не создаёт: переменная 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
Объявите класс Drink заново, с тремя атрибутами: name, price и size. Размер по умолчанию — "M":
Drink("Чай", 120) создаёт средний чай, а Drink("Чай", 150, "L") — большой.
def __init__(self, name, price, size="M"):.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Drink:
def __init__(self, name, price): # добавьте параметр size
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Drink:
def __init__(self, name, price, size="M"):
self.name = name
self.price = price
self.size = 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
Объявите класс Customer: Customer("Анна", "+7 900 111-22-33") создаёт покупателя с атрибутами name
и phone из аргументов и points — баллами лояльности. У нового покупателя их 0, и передавать их при
создании не нужно.
points нет среди параметров: в __init__ просто self.points = 0.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Customer:
def __init__(self, name, phone):
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
class Customer:
def __init__(self, name, phone):
self.name = name
self.phone = phone
self.points = 0Много экземпляров
Экземпляры удобно создавать в цикле: класс вызывается с разными аргументами, а объекты складываются в список.
В data — пары «название, цена». Создайте список menu из экземпляров Drink (из упражнения про размер)
по этим данным — в том же порядке, размер у всех по умолчанию.
[Drink(name, price) for name, price in data].Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
data = [("Эспрессо", 150), ("Капучино", 220), ("Раф", 260)]
menu = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
data = [("Эспрессо", 150), ("Капучино", 220), ("Раф", 260)]
menu = [Drink(name, price) for name, price in data]