property и __slots__
Два прикладных вопроса по ООП: управляемые атрибуты через property и экономия памяти через __slots__.
@propertyпревращает метод в «вычисляемый атрибут»: доступ как к полю, но с логикой внутри.__slots__ограничивает набор атрибутов и убирает у объекта словарь__dict__.
property: атрибут с логикой и валидацией
Чёткий ответ. property позволяет обращаться к методу как к атрибуту (obj.x вместо obj.x()) и добавить проверку при чтении/записи, не меняя внешний интерфейс.
class Celsius:
def __init__(self, t=0):
self._t = t
@property
def temperature(self):
return self._t
@temperature.setter
def temperature(self, value):
if value < -273.15:
raise ValueError("ниже абсолютного нуля")
self._t = value
@property
def fahrenheit(self): # вычисляемый атрибут
return self._t * 9 / 5 + 32
c = Celsius(25)
print("по Фаренгейту:", c.fahrenheit)
c.temperature = 100 # вызовет setter с проверкой
print("по Фаренгейту:", c.fahrenheit)
Вывод:
по Фаренгейту: 77.0 по Фаренгейту: 212.0
Снаружи c.fahrenheit выглядит как обычное поле, но считается на лету. А запись в c.temperature проходит через проверку — попытка задать значение ниже абсолютного нуля вызовет ошибку.
__slots__: меньше памяти, фиксированный набор полей
По умолчанию атрибуты объекта хранятся в словаре __dict__ — это гибко, но затратно по памяти. __slots__ объявляет жёсткий список полей: словарь не создаётся, экземпляры легче, а добавить новый атрибут уже нельзя.
class WithSlots:
__slots__ = ("x", "y") # разрешены только x и y
def __init__(self, x, y):
self.x, self.y = x, y
w = WithSlots(1, 2)
print(w.x, w.y)
try:
w.z = 3 # нового поля нет в слотах
print("z добавлен")
except AttributeError:
print("нельзя добавить атрибут z")
Вывод:
1 2 нельзя добавить атрибут z
Когда что применять
@property— когда нужен контроль доступа или вычисляемое поле, сохранив простой интерфейсobj.attr.__slots__— когда создаётся очень много мелких объектов и важна память (например, миллионы точек).
Итог
@propertyдаёт доступ к методу как к атрибуту и место для валидации в setter.__slots__убирает__dict__, экономит память и фиксирует список атрибутов.- В классе со
__slots__нельзя завести атрибут, которого нет в списке.
Проверьте себя
1. Что делает @property?
AДелает атрибут приватным
BПозволяет обращаться к методу как к атрибуту и добавить логику доступа
CУскоряет класс
DСоздаёт статический метод
2. Что даёт __slots__?
AДелает класс быстрее в наследовании
BУбирает __dict__, экономит память и фиксирует набор атрибутов
CРазрешает любые атрибуты
DВключает многопоточность
3. Что произойдёт при попытке задать атрибут вне __slots__?
AОн создастся в __dict__
BБудет AttributeError
CПрограмма зависнет
DАтрибут проигнорируется молча