2 типа дескрипторов в Python
В этом руководстве вы узнаете о различиях между дескрипторами данных и дескрипторами, не относящимися к данным.
Дескрипторы в Python бывают двух типов:
- Дескрипторы данных — это объекты класса, реализующего метод __set__(и/или метод __delete__).
- Дескрипторы, не являющиеся данными, — это объекты класса, имеющие только метод __get__.
Оба типа дескрипторов могут опционально реализовывать метод __set_name__. Метод __set_name__ не влияет на классификацию дескрипторов.
Типы дескрипторов определяют, как Python разрешает поиск атрибутов объекта.
Дескриптор без данных
Если класс использует дескриптор, не являющийся данными, Python сначала будет искать атрибут в атрибутах экземпляра (instance.__dict__). Если Python не находит атрибут в атрибутах экземпляра, он будет использовать дескриптор данных.
Давайте посмотрим на следующий пример.
- Сначала определите класс FileCount, не являющийся дескриптором данных, который имеет метод __get__, который возвращает количество файлов в папке:
class FileCount: def __get__(self, instance, owner): print('The __get__ was called') return len(os.listdir(instance.path))
- Во-вторых, определите класс Folder, который использует дескриптор FileCount:
class Folder: count = FileCount() def __init__(self, path): self.path = path
- В-третьих, создайте экземпляр класса Folder и получите доступ к атрибуту count:
folder = Folder('/') print('file count: ', folder.count)
Python вызвал дескриптор __get__:
The __get__ was called file count: 32
- После этого установите атрибут count экземпляра папки на 100 и получите доступ к атрибуту count:
folder.__dict__['count'] = 100 print('file count: ', folder.count)
Выход:
file count: 100
В этом примере Python может найти атрибут count в словаре экземпляра __dict__. Поэтому он не использует дескрипторы данных.
Дескриптор данных
Если у класса есть дескриптор данных, Python сначала будет искать атрибут экземпляра в дескрипторе данных. Если Python не находит атрибут, он будет искать его в словаре экземпляра(__dict__).
Пример:
- Сначала определите класс дескриптора координат:
class Coordinate: def __get__(self, instance, owner): print('The __get__ was called') def __set__(self, instance, value): print('The __set__ was called')
- Во-вторых, определите класс Point, который использует дескриптор координат:
class Point: x = Coordinate() y = Coordinate()
- В-третьих, создайте новый экземпляр класса Point и присвойте значение атрибуту x экземпляра p:
p = Point() p.x = 10
Выход:
The __set__ was called
Python вызвал метод __set__ дескриптора x.
- Наконец, получите доступ к атрибуту x экземпляра p:
p.x
Выход:
The __get__ was called
Python вызвал метод __get__ дескриптора x.