Что происходит при добавлении нового атрибута в объект Python
Что проверяют
Понимаете ли вы, где физически живут атрибуты экземпляра и что происходит при присваивании. Вопрос выводит на словарь объекта, __slots__ и дескрипторы, то есть на устройство объектной модели, а не на синтаксис.
Как отвечать
Присваивание obj.x = 1 это вызов type(obj).__setattr__. Реализация по умолчанию сначала смотрит в классе и его предках: если там нашёлся дескриптор данных, например property с сеттером, управление уходит туда. Иначе значение кладётся в словарь экземпляра obj.__dict__, и оттуда же читается потом, причём раньше одноимённого атрибута класса.
class Point: pass
p = Point()
p.z = 3
p.__dict__ # {'z': 3}
Point().z # AttributeError: у другого экземпляра его нетСледствия, которые стоит перечислить:
- атрибут появляется только у этого объекта, класс и остальные экземпляры не меняются;
- у класса со
__slots__словаря нет, и присваивание нового имени даётAttributeError; - встроенным типам и многим объектам из расширений на C атрибут тоже не добавить;
del obj.xубирает запись из словаря экземпляра, после чего снова становится виден атрибут класса, если он есть.
Про память полезно знать, что интерпретатор хранит ключи словарей экземпляров одного класса совместно, пока набор имён у всех одинаков. Атрибут, добавленный позже и не всем объектам, это разделение ломает, и на миллионах объектов разница в потреблении заметна.
Где спотыкаются
Объясняют возможность динамической типизацией. Дело не в ней: типизация про значения, а дописать имя можно потому, что атрибуты лежат в обычном изменяемом словаре.
Второе: считают такую подвижность чистым удобством. Опечатка в имени не вызывает ошибки, а молча заводит новый атрибут, и объект расходится с тем, что о нём думает остальной код. Поэтому набор полей фиксируют через __slots__, dataclass или схему валидации.
Третье: путают присваивание экземпляру и классу. Запись в класс меняет поведение всех объектов сразу, включая созданные раньше, и особенно больно это с изменяемым значением: список, объявленный в теле класса, окажется общим для всех.