Посмотрите на классы из прошлых модулей: Product, Money, Customer. В каждом — одинаковый __init__,
который переписывает параметры в атрибуты, __repr__, который их перечисляет, и __eq__, который их
сравнивает. Это много однообразного кода, в котором легко ошибиться: добавили атрибут — и забыли его в
__eq__. Для таких классов данных (data class) в стандартной библиотеке есть модуль dataclasses.
@dataclass
Декоратор @dataclass читает список полей (field) класса и сам пишет __init__, __repr__ и __eq__.
Поле объявляется в теле класса строкой имя: тип — это аннотация типа (type annotation): подсказка,
какого типа значение ожидается.
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: int
latte = Product("Латте", 220)
print(latte)
print(latte == Product("Латте", 220), latte == Product("Латте", 250))
print(latte.name, latte.price)Product(name='Латте', price=220) True False Латте 220
Три строки полей заменили собой три метода. __repr__ перечисляет поля с именами, __eq__ сравнивает все
поля по порядку.
Объявите dataclass Drink с полями name (строка), price (целое) и volume (целое). Свой __init__ не
пишите — его создаст декоратор.
Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
from dataclasses import dataclass
class Drink:
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
from dataclasses import dataclass
@dataclass
class Drink:
name: str
price: int
volume: intЗначения по умолчанию
Значение по умолчанию задают прямо в поле: volume: int = 250. Поля со значением по умолчанию идут после
полей без него — как параметры функции:
@dataclass
class Cup:
name: str
volume: int = 250
print(Cup("Капучино"), Cup("Капучино", 400))Cup(name='Капучино', volume=250) Cup(name='Капучино', volume=400)
Методы и свойства в dataclass объявляются как обычно — декоратор их не трогает:
Объявите dataclass OrderLine с полями product (строка), price (целое) и qty (целое, по умолчанию 1)
и свойством cost — стоимость строки, цена на количество.
Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class OrderLine:
...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
@dataclass
class OrderLine:
product: str
price: int
qty: int = 1
@property
def cost(self):
return self.price * self.qtyСписки в полях: default_factory
Помните изменяемое значение по умолчанию из модуля 2? dataclass не даёт на него наступить — поле
items: list = [] вызывает ошибку сразу при объявлении класса:
@dataclass
class Basket:
customer: str
items: list = []ValueError: mutable default <class 'list'> for field items is not allowed: use default_factory
Нужно сказать, как создавать значение для каждого нового экземпляра: field(default_factory=list) —
вызвать list() и получить новый пустой список. field импортируют из того же модуля:
from dataclasses import dataclass, field
@dataclass
class Basket:
customer: str
items: list = field(default_factory=list)
anna, boris = Basket("Анна"), Basket("Борис")
anna.items.append("Латте")
print(anna)
print(boris)Basket(customer='Анна', items=['Латте']) Basket(customer='Борис', items=[])
Перепишите класс Customer из заготовки на dataclass: поля name, phone, points (по умолчанию 0) и
visits — список дат визитов, у каждого покупателя свой, по умолчанию пустой. Метод visit(date) добавляет
дату в visits и начисляет 10 баллов — его перенесите без изменений.
@dataclass; __init__, __repr__ и __eq__ из заготовки удалите — их напишет декоратор.field(default_factory=…).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
class Customer:
def __init__(self, name, phone, points=0, visits=None):
self.name = name
self.phone = phone
self.points = points
self.visits = [] if visits is None else visits
def __repr__(self):
return f"Customer(name={self.name!r}, phone={self.phone!r}, points={self.points!r}, visits={self.visits!r})"
def __eq__(self, other):
if not isinstance(other, Customer):
return NotImplemented
return (self.name, self.phone, self.points, self.visits) == (other.name, other.phone, other.points, other.visits)
def visit(self, date):
self.visits.append(date)
self.points += 10Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
from dataclasses import dataclass, field
@dataclass
class Customer:
name: str
phone: str
points: int = 0
visits: list = field(default_factory=list)
def visit(self, date):
self.visits.append(date)
self.points += 10