Конструктори и self
Проблем
Кафе за 0 €
Създаваш продукт, както в миналия урок, и попълваш полетата ред по ред. Един ред си забравил:
coffee = Product()coffee.name = "Кафе"coffee.quantity = 2print(f"{coffee.name}: {coffee.price * coffee.quantity} €")Кафе: 0.0 €Кафето струва 0 €. Python не се оплаква: цената си има стойност, 0.0 от __init__. Колкото повече полета има класът, толкова по-лесно е да пропуснеш едно. А продукт без цена не трябва изобщо да може да съществува.
Идеята
Конструктор: без тези данни няма обект
Класът може да каже какво е нужно, за да се създаде обект от него. За това служи конструкторът: специален метод, който се изпълнява при Product(...). В Python това е __init__, който вече видя, само че сега получава параметри.
class Product: def __init__(self, name, price, quantity): self.name = name self.price = price self.quantity = quantity
coffee = Product("Кафе", 7.50, 2)print(f"{coffee.name}: {coffee.price * coffee.quantity} €")Кафе: 15.0 €- Конструкторът се казва
__init__(две долни черти отпред и две отзад), във всеки клас. - Първият му параметър е
self: обектът, който се създава. Python го подава сам. - Останалите параметри са данните, без които продукт няма. Те се подават в скобите:
Product("Кафе", 7.50, 2). - Нищо не връща.
Product(...)връща новия обект.
Сега няма как да забравиш цената. Ако подадеш два аргумента вместо три, програмата спира още на този ред:
coffee = Product("Кафе", 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("Кафе", 7.50, 2)print(f"{coffee.name}: {coffee.price * coffee.quantity} €")Стъпка по стъпка, с думи
- Product(...) прави нов обект. Полета още няма: ще ги създаде __init__.
- Изпълнява се __init__. self е новият обект, а аргументите отиват в параметрите.
- self.name = name: от параметъра в ново поле на този обект.
- Същото за цената и бройката.
- __init__ свърши и параметрите изчезват. В coffee отива стрелка към готовия обект.
- Обектът излиза от Product(...) вече попълнен, затова цената не е 0.
Идеята
self: полето на този обект
Вътре в __init__ има две неща с име name: параметърът и полето. name е параметърът. Полето е self.name.
class Product: def __init__(self, name, price, quantity): self.name = name self.price = price self.quantity = quantityself е обектът, който се създава в момента. self.name = name значи „в полето name на този обект запиши параметъра name“.
В Python self. е задължително. Без него name = name е просто променлива вътре в __init__, която изчезва, щом той свърши. Името self е договорка, а не ключова дума, но така го пишат всички.
Пробвай
Намери грешката
AttributeError: 'Product' object has no attribute 'name'. На кой ред е грешката?Избери реда с грешката.
name = name записва параметъра в самия него. Полето name изобщо не се създава, затова tea.name го няма. Трябва self.name = name. Грешката излиза чак на реда, който чете името, далеч от истинската причина.
Идеята
А Product() от миналия урок?
В миналия урок __init__ нямаше параметри освен self, затова Product() работеше. Сега __init__ иска три аргумента и без тях програмата спира:
empty = Product()TypeError: Product.__init__() missing 3 required positional arguments: 'name', 'price', and 'quantity'Това е целта: продукт без име и цена вече не може да се създаде.
По-точно, за любопитните
Ако клас изобщо няма __init__, Product() пак работи: Python създава обект без нито едно поле. Затова полетата в Python винаги се създават в __init__.
Идеята
Бройка по подразбиране
Повечето продукти в количката са по един брой. Да пишеш 1 всеки път е досадно.
В Python класът има един __init__. Вместо втори конструктор параметърът получава стойност по подразбиране: ако не подадеш бройка, тя е 1.
class Product: def __init__(self, name, price, quantity=1): self.name = name self.price = price self.quantity = quantityquantity=1 (без интервали около =) значи „ако бройка не е подадена, вземи 1“. Параметрите със стойност по подразбиране са последни. Ако след quantity=1 сложиш параметър без стойност, Python не пуска файла:
SyntaxError: parameter without a default follows parameter with a defaultПо-точно, за любопитните
Втори __init__ в класа не прави втори конструктор. Той просто заменя първия, без предупреждение, и Product("Хляб", 1.20) спира с:
TypeError: Product.__init__() missing 1 required positional argument: 'quantity'Затова в Python има само един конструктор. Предимството: ако утре добавиш проверка на цената, тя е на едно място.
Пробвай
Кой конструктор?
Какво ще отпечата програмата?
class Product: def __init__(self, name, price, quantity=1): self.name = name self.price = price self.quantity = quantity
bread = Product("Хляб", 1.20)milk = Product("Мляко", 2.10, 3)print(bread.quantity, milk.quantity)Product("Хляб", 1.20) няма бройка, затова quantity взима стойността по подразбиране 1. За млякото бройката е подадена: 3.Пробвай
Как се казва конструкторът?
Какво трябва да пише на празното място?
class Book:
def (self, title, author):
self.title = title
self.author = author__init__: така се казва конструкторът във всеки клас, с по две долни черти.Упражнение
Обекти, създадени цели
Реши задачите в редактора си. Всеки клас получава конструктор с параметри за всички полета.
1. Човек. Клас Person с име и възраст. Създай двама души и отпечатай данните им.
Мария, 34 г.Петър, 19 г.2. Животно. Клас Animal с вид и възраст. Създай котка на 3 и куче на 7 години.
Вид: котка, възраст: 3Вид: куче, възраст: 73. Танцова стъпка. Клас DanceMove с име и продължителност в секунди. В урока „Поведение“ стъпката ще се научи да се „изпълнява“.
moonwalk: 5 сек.Още задачи
- Книга с конструктор. Препиши
Bookот миналия урок с конструктор__init__(self, title, author). Колко реда спести в кода под класа? -
Продукт с бройка по подразбиране.
Productсquantity=1, както в урока. Направи списък[Product("Хляб", 1.20, 2), Product("Кафе", 7.50)]и отпечатай името и бройката на всеки: „Хляб x2“, „Кафе x1“. - Резервация. Клас
Bookingс име на госта, брой нощувки и цена за нощувка. Отпечатай колко струва престоят: за 3 нощувки по 85 € това е 255 €.
Тест