Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
slots в Python
slots — это специальный атрибут класса, который ограничивает набор атрибутов экземпляра и уменьшает использование памяти. Вместо использования словаря dict для хранения атрибутов, slots использует фиксированный массив.
Зачем нужен slots
- Экономия памяти — уменьшает использование памяти на 40-50%
- Небольшое ускорение — быстрее доступ к атрибутам
- Защита от опечаток — нельзя добавлять новые атрибуты
- Контроль интерфейса — явно определяешь, какие атрибуты может иметь объект
Как работает без slots
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 30)
# Каждый объект имеет словарь __dict__ для хранения атрибутов
print(person.__dict__) # {'name': 'Alice', 'age': 30}
# Можно добавить новый атрибут в любой момент
person.email = "alice@example.com"
print(person.__dict__) # {'name': 'Alice', 'age': 30, 'email': 'alice@example.com'}
# Это требует дополнительной памяти для каждого объекта
import sys
print(sys.getsizeof(person.__dict__)) # 280 байт на словарь
Использование slots
class Person:
__slots__ = ['name', 'age', 'email']
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 30)
# Объект больше не имеет __dict__
print(hasattr(person, '__dict__')) # False
# Можно установить определённые атрибуты
person.email = "alice@example.com"
print(person.name) # Alice
print(person.email) # alice@example.com
# Но НЕЛЬЗЯ добавлять новые атрибуты
person.phone = "123-456-7890" # AttributeError: 'Person' object has no attribute 'phone'
Сравнение памяти
import sys
class PersonWithDict:
def __init__(self, name, age):
self.name = name
self.age = age
class PersonWithSlots:
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age
# Сравниваем размер
with_dict = PersonWithDict("Alice", 30)
with_slots = PersonWithSlots("Alice", 30)
print(f"С __dict__: {sys.getsizeof(with_dict)} байт")
print(f"Со __slots__: {sys.getsizeof(with_slots)} байт")
# Если создать миллион объектов:
objects_dict = [PersonWithDict(f"User{i}", i) for i in range(1000000)]
objects_slots = [PersonWithSlots(f"User{i}", i) for i in range(1000000)]
import gc
gc.collect()
# __slots__ экономит десятки МБ памяти
print(sys.getsizeof(objects_dict)) # ~70+ МБ
print(sys.getsizeof(objects_slots)) # ~30+ МБ
slots с наследованием
class Animal:
__slots__ = ['name']
class Dog(Animal):
__slots__ = ['breed'] # Только новые атрибуты
def __init__(self, name, breed):
self.name = name
self.breed = breed
dog = Dog("Rex", "Labrador")
print(dog.name) # Rex
print(dog.breed) # Labrador
# ВАЖНО: если родитель не использует __slots__, потомок будет иметь __dict__
class Animal:
pass
class Dog(Animal):
__slots__ = ['breed'] # Это НЕ сэкономит память
dog = Dog()
dog.name = "Rex" # Это сработает, несмотря на __slots__
Ограничения slots
class Person:
__slots__ = ['name', 'age']
person = Person()
# 1. Нельзя присваивать __dict__
person.__dict__ = {} # AttributeError
# 2. Нельзя использовать слабые ссылки (weak references)
# import weakref
# weakref.ref(person) # TypeError
# 3. Нельзя добавлять методы класса динамически
Person.new_method = lambda self: None # Это сработает, но приведёт к проблемам
# 4. Сложнее при множественном наследовании
class Mixin:
__slots__ = ['x']
class Base:
__slots__ = ['y']
class Derived(Mixin, Base): # Может быть сложнее
__slots__ = ['z']
slots и производительность
import timeit
class WithDict:
def __init__(self, x):
self.x = x
class WithSlots:
__slots__ = ['x']
def __init__(self, x):
self.x = x
# Доступ к атрибутам немного быстрее
time_dict = timeit.timeit(lambda: WithDict(1).x, number=1000000)
time_slots = timeit.timeit(lambda: WithSlots(1).x, number=1000000)
print(f"__dict__: {time_dict}")
print(f"__slots__: {time_slots}")
# __slots__ примерно на 10-20% быстрее
Когда использовать slots
Используй slots, если:
- Создаёшь большое количество объектов (тысячи и миллионы)
- Память критична (встраиваемые системы, мобильные приложения)
- Атрибуты фиксированы и не меняются
- Нужна защита от опечаток
class Point:
__slots__ = ['x', 'y', 'z']
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
# Создание миллионов точек для 3D графики
points = [Point(i, i+1, i+2) for i in range(1000000)]
НЕ используй slots, если:
- Нужна гибкость добавления новых атрибутов
- Используешь множественное наследование
- Нужны слабые ссылки
- Объектов немного (экономия памяти не критична)
Практический пример: ORM модель
class DBModel:
__slots__ = ['id', 'name', 'email', 'created_at']
def __init__(self, id, name, email, created_at):
self.id = id
self.name = name
self.email = email
self.created_at = created_at
# Если в БД миллионы записей, это значительно сэкономит память
records = [DBModel(i, f"User{i}", f"user{i}@example.com", None) for i in range(1000000)]
Выводы
slots — это инструмент оптимизации памяти и производительности:
- Экономит 40-50% памяти
- Немного ускоряет доступ к атрибутам
- Защищает от случайных опечаток
- Имеет ограничения и усложняет наследование
Используй slots в специфических случаях, когда это действительно необходимо. В большинстве приложений это не требуется.