Что такое дескрипторы данных?



Очень часто переменные, инициализируемые в классе, являются однотипными. Например, есть класс 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: Минимум две буквы в атрибуте требуется



@python_job_interview