Что такое модель памяти Python? Что такое __slots__?

Высокоуровневая модель памяти Python (CPython) выглядит так: все объекты живут в куче, на них ссылаются переменные и структуры данных, память управляется через подсчёт ссылок плюс сборщик мусора для циклических ссылок, а стек функций хранит только ссылки, а не «значения» как таковые. __slots__ — это специальный атрибут класса, который отключает обычный __dict__ для экземпляров и заранее объявляет фиксированный набор полей; в результате экземпляры занимают меньше памяти и немного быстрее работают с атрибутами, но теряют динамическое добавление новых полей.

Подробный ответ

Куча (heap) - все объекты (числа, строки, списки, экземпляры классов и т.д.) живут в куче — области памяти, управляемой интерпретатором.

Стек вызовов - для каждой вызываемой функции создаётся фрейм на стеке: локальные переменные, аргументы, ссылки на объекты в куче.

Важный момент: локальная переменная x — это не сам объект, а ссылка на него.

Подсчёт ссылок + GC

У объекта есть счётчик ссылок; когда он падает до нуля, объект сразу освобождается, память возвращается аллокатору. Для циклов ссылок поверх этого работает генерационный сборщик мусора.

Модель «всё — объект»

Даже функции, классы и модули — объекты в куче, на которые ссылаются имена в пространствах имён. Ответ для middle‑специалиста обычно ожидают на уровне: «объекты в куче, ссылки на них в стеке, управление памятью через подсчёт ссылок плюс GC для циклов».

Что делает __slots__

По умолчанию у каждого экземпляра пользовательского класса есть словарь __dict__, где хранятся его атрибуты:

class User:
   def __init__(self, name, age):
       self.name = name
       self.age = age
       
u = User("Ann", 30)
print(u.__dict__)  # {'name': 'Ann', 'age': 30}

Это даёт гибкость (можно в любой момент дописать u.foo = 1), но у словаря есть цена: память и скорость доступа. Если в классе объявить __slots__, Python не будет создавать __dict__ для экземпляров, а вместо этого выделит фиксированную структуру под указанные атрибуты:

class User:
   __slots__ = ("name", "age")
   def __init__(self, name, age):
       self.name = name
       self.age = age
       
u = User("Ann", 30)
# u.__dict__  -> AttributeError: 'User' object has no attribute '__dict__'

Эффекты коллекции __slots__

  1. Экономия памяти. Для большого количества однотипных объектов (например, миллионов DTO или ORM‑моделей) экономия может составлять 20–50% на экземпляр.

  2. Более быстрый доступ к атрибутам. Доступ идёт по смещению в фиксированной структуре, а не через словарь → обычно даёт прирост 10–20% к скорости доступа к полям.

  3. Запрет произвольных атрибутов. Нельзя написать u.foo = 1, если foo не объявлен в __slots__ — будет AttributeError. Это иногда используют как способ ограничить интерфейс объектов и ловить опечатки вместо тихого создания нового поля.

Ограничения и нюансы __slots__

На собеседовании хорошо упомянуть не только плюсы, но и ограничения:

  1. __slots__ не наследуются автоматически как ожидают новички — при сложной иерархии классов нужно аккуратно их проектировать, учитывая, как объединяются слоты базовых и дочерних классов.

  2. Экземпляр класса с __slots__ по умолчанию не имеет __dict__ и __weakref__; если они нужны, их нужно явно добавить в __slots__.

  3. __slots__ разумно применять там, где:

- очень много однотипных объектов (модели, ноды AST, структуры данных);

- набор полей стабилен и заранее известен;

- важны память и скорость доступа.

В обычном бизнес‑коде для нескольких десятков объектов выгода минимальна, а гибкость теряется.

Модель памяти Python: объекты живут в куче, переменные — это ссылки на них в стеке и словарях пространств имён, память управляется подсчётом ссылок и генерационным GC для циклических ссылок. __slots__ — это настройка класса, которая отключает словарь атрибутов __dict__ у экземпляров и заменяет его фиксированной структурой с заранее объявленными полями. Это уменьшает память на экземпляр и ускоряет доступ к атрибутам, но запрещает динамически добавлять новые поля и требует аккуратности при наследовании.

Оцени свой прогресс

Честно оцени своё понимание этого вопроса, чтобы мы могли построить твой учебный трек максимально эффективно.
Читать в блоге