Дескрипторы — это мощный механизм управления доступом к атрибутам объектов, который лежит в основе многих встроенных возможностей Python, таких как свойства (property
), методы классов (classmethod
, staticmethod
) и слоты (__slots__
).
Дескриптор — это любой объект, который реализует хотя бы один из трех специальных методов:
__get__(self, obj, type=None)
— для получения значения__set__(self, obj, value)
— для установки значения__delete__(self, obj)
— для удаления атрибутаРеализует __set__
и/или __delete__
в дополнение к __get__
class DataDescriptor:
def __get__(self, obj, objtype=None):
print("Получение значения")
return obj._value
def __set__(self, obj, value):
print("Установка значения")
obj._value = value
class MyClass:
attr = DataDescriptor() # Дескриптор данных
Реализует только __get__
class NonDataDescriptor:
def __get__(self, obj, objtype=None):
print("Получение значения (non-data)")
return 42
class MyClass:
attr = NonDataDescriptor() # Не-дескриптор данных
class ValidatedAttribute:
def __init__(self, name, type_, default=None):
self.name = name
self.type = type_
self.default = default
def __get__(self, obj, objtype):
if obj is None:
return self
return getattr(obj, f"_{self.name}", self.default)
def __set__(self, obj, value):
if not isinstance(value, self.type):
raise TypeError(f"Ожидается {self.type}, получено {type(value)}")
setattr(obj, f"_{self.name}", value)
class Person:
name = ValidatedAttribute("name", str)
age = ValidatedAttribute("age", int, 0)
# Использование
p = Person()
p.name = "Иван" # OK
p.age = 30 # OK
p.age = "30" # Вызовет TypeError
При доступе к атрибуту Python следует алгоритму:
__dict__
экземпляра__getattr__
(если определен)property
— самый распространенный дескрипторclass Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Радиус не может быть отрицательным")
self._radius = value
classmethod
и staticmethod
также реализованы через дескрипторыobj is None
в __get__
property
, classmethod
, staticmethod
Дескрипторы — это продвинутая, но очень мощная возможность Python, которую стоит освоить для написания идиоматического и поддерживаемого кода.