Почему метод дескриптора python __get__ принимает класс владельца как arg?

Почему метод __get__ в дескрипторе python принимает класс владельца как третий аргумент? Можете ли вы привести пример использования?

Первый аргумент (self) самоочевиден, второй (instances) имеет смысл в контексте типично отображаемого шаблона дескриптора (ex to follow), но я никогда не видел третьего (owner). Может ли кто-нибудь объяснить, что используется для этого?

Просто в качестве справки и облегчения ответов это типичное использование дескрипторов, которые я видел:

class Container(object):
    class ExampleDescriptor(object):
        def __get__(self, instance, owner):
            return instance._name 
        def __set__(self, instance, value):
            instance._name = value
    managed_attr = ExampleDescriptor()

Учитывая, что доступно instance.__class__, все, что я могу представить, это то, что явно передача класса имеет непосредственное отношение к дескриптору из класса вместо экземпляров (ex Container.managed_attr). Тем не менее, я не понимаю, что можно было бы сделать в __get__ в этой ситуации.

Ответы

Ответ 1

owner используется, когда атрибут получает доступ из класса вместо экземпляра класса, и в этом случае instance будет None.

В вашем примере попытка выполнить что-то вроде print(Container.managed_attr) завершится неудачно, потому что instance есть None, поэтому instance._name поднимет AttributeError.

Вы можете улучшить это поведение, проверив, есть ли instance is None, и может быть полезно для ведения журнала или создания более полезного исключения, чтобы узнать, к какому классу принадлежит дескриптор, следовательно, атрибуту owner. Например:

        def __get__(self, instance, owner):
            if instance is None:
                # special handling for Customer.managed_attr
            else:
                return instance._name 

Ответ 2

Когда доступ к дескриптору из класса, instance будет None. Если вы не учли эту ситуацию (как не показано в примере вашего кода), тогда в этой точке произойдет ошибка.

Что вы должны делать в этом случае? Что бы ни было разумно.;) Если ничего другого не имеет смысла, вы можете следовать примеру property и возвращать сам дескриптор при доступе к нему из класса.

Ответ 3

Да, он используется так, чтобы дескриптор мог видеть Контейнер при доступе к контейнеру .managed_attr. Вы можете вернуть некоторый объект, подходящий для использования, например, метод unbound, когда дескрипторы используются для реализации методов.