9,4K подписчиков
❓Что такое дескрипторы данных?

Очень часто переменные, инициализируемые в классе, являются однотипными. Например, есть класс Employee (сотрудник), принимающий параметры: имя, фамилия, отчество, должность. Все они являются строками. Следовательно, прежде чем создать экземпляр класса, нужно проверить, что пользователь ввел строки. А для этого потребуются сеттеры, проверяющие тип вводимых параметров. В итоге, мы 4 раза повторим код проверки. Нарушается принцип DRY (don't repeat yourself).

Для таких ситуаций удобно использовать дескрипторы (они, к слову, широко применяются во фреймворке Django при создании моделей).

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

Существует 4 метода протокола дескрипторов:
get__() - получить значение свойства;
set__() - задать значение;
delete__() - удалить атрибут;
set_name__() - присвоить имя свойству (появился в Питоне версии 3.6).

Если применяется только метод __get__(), то мы имеем дело с дескриптором без данных, а если есть еще и __set__(), то речь будет идти о дескрипторе данных.

Покажем использование дескрипторов на вышеупомянутом примере.

Пример – IDE
---
# Создаем класс с протоколами дескриптора
class StringChecker:

# Получаем доступ к свойству
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.name]

# Меняем свойство
def __set__(self, instance, str_value):
if not isinstance(str_value, str):
raise ValueError('Нужно предоставить строку')
elif len(str_value) < 2:
raise ValueError('Необходимо минимум 2 буквы')
instance.__dict__[self.name] = str_value

# Задаем имя свойства
def __set_name__(self, owner, name):
self.name = name

class Employee:

# Определяем атрибуты (их может быть любое количество)
name = StringChecker()
surname = StringChecker()
patronymic = StringChecker()
post = StringChecker()

# Инициализируем свойства с учетом требуемых проверок
def __init__(self, name, surname, patronymic, post):
self.name = name
self.surname = surname
self.patronymic = patronymic
self.post = post

# Тесты
director = Employee('Иван', 'Николаевич', 'Прогин', 'Директор')
print(director.__dict__)
director.name = 1
director.name = 'A'

Результат выполнения
---
{'name': 'Иван', 'surname': 'Николаевич', 'patronymic': 'Прогин', 'post': 'Директор'}
ValueError: Нужно предоставить строку
ValueError: Минимум две буквы в атрибуте требуется

11 месяцев назад