Ти пишеш @dataclass над класом і оголошуєш поле рядком «кількість = 0» — без двокрапки й без типу. Що станеться?
Клас.__annotations__). Рядок без двокрапки для нього невидимий — залишається звичайний атрибут класу, спільний на всі примірники. Помилки не буде, і саме це найнеприємніше: Продаж(кількість=5) впаде з TypeError зовсім в іншому місці.У класі під @dataclass написано «теги: list = []». Коли ти дізнаєшся, що це погана ідея?
list, dict і set у замовчуванні й відмовляється створювати клас. У темі 15 та сама пастка у функції def додати(товар, кошик=[]) не викликала жодного заперечення й тихо накопичувала значення між викликами — у цьому й уся різниця. Помилка, яка кричить одразу, дешевша за помилку, яка мовчить.Клас під простим @dataclass, полів два, обидва порівнюються. Чому «{продаж}» падає з TypeError: unhashable type?
__eq__ руками. Повертає хеш frozen=True.Клас оголошено як @dataclass(frozen=True), серед полів є «теги: list». Що зробить рядок p.теги.append("акція")?
frozen дописує __setattr__, який забороняє перепризначити поле — переклеїти ярлик на інший обʼєкт. Список за цим ярликом лишається звичайним змінюваним списком із теми 06, і append нікого не питає. Справжня незмінність починається тоді, коли незмінні всі поля: заміни список кортежем.У класі є поле «сума: float = field(init=False)». Звідки візьметься його значення?
init=False прибирає поле із сигнатури __init__, тому передати його ззовні неможливо — і в цьому сенс: обчислюване значення не має приймати чужі дані. Заповнюють його в __post_init__, який виконується після того, як усі звичайні поля вже записані, тож у ньому доступне будь-яке з них.У __post_init__ спрацював raise ValueError. Що станеться з обʼєктом, у якому на цей момент уже записані всі пʼять полів?
__post_init__ виконується всередині __init__, тож виняток з нього вилітає прямо з конструктора. Імʼя ні до чого не привʼязується, і напівживий обʼєкт просто нікому не дістається. Саме тому перевірки ставлять сюди, а не в окремий метод, який хтось може забути покликати.Виміряно: звичайний dataclass із пʼятьма полями — 104 байти на обʼєкт, зі slots=True — 72. У програмі таких обʼєктів десять тисяч. Що робити?
__dict__, а з ним — можливість додати поле на льоту й частину бібліотек, що на цей словник розраховують. slots=True — інструмент для мільйонів однотипних записів, а не звичка на кожен клас: спершу зміряй, потім міняй.Потрібен тип для запису «код валюти + курс»: поля відомі наперед, обʼєкт має бути незмінним і лягати в множину, жодних перевірок і методів. Що дешевше?
NamedTuple дешевший: він незмінний за визначенням, хешується, займає менше памʼяті й розпаковується як кортеж (код, курс = запис). dataclass виграє тоді, коли треба перевіряти дані при створенні, міняти поля після створення або тримати помітну поведінку — тут нічого з цього немає.