2016-11-08 6 views
0

Я пытаюсь обернуть голову концепцией дескрипторов, и в последнее время у меня не было успеха. Это article дескриптора. Как действительно помогло, и в то же время оно меня тоже смутило. Я борюсь с этим примером здесь почему m.x называет def __get__(self, obj, objtype):Понимание примера дескриптора из статьи «descriptors howto»

class RevealAccess(object): 
    def __init__(self, initval=None, name='var'): 
     self.val = initval 
     self.name = name 

    def __get__(self, obj, objtype): 
     print('Retrieving', self.name) 
     return self.val 

    def __set__(self, obj, val): 
     print('Updating', self.name) 
     self.val = val 

>>> class MyClass(object): 
...  x = RevealAccess(10, 'var "x"') 
...  y = 5 
... 
>>> m = MyClass() 
>>> m.x 
Retrieving var "x" 
10 

Я считаю, что причина я борюсь с этим, потому что я смущен следующим утверждением в статье

Подробности о вызов зависит от того, является ли объект obj или классом . Для объектов оборудование находится в object.__getattribute__() , который преобразует b.x в type(b).__dict__['x'].__get__(b, type(b)). Реализация работает через очередность цепь, которая отдает приоритет данные дескрипторов над переменным экземпляром, переменного экземпляром приоритета над дескрипторами без данных, и присваивает низкий приоритет __getattr__() при условии

Я не уверен, что автор означает здесь объект или класс. Объект означает экземпляр класса? Я понимаю, что когда мы делаем instance.var, python внутренне делает instance.__dict__["var"], если это не найдено, то это class.__dict__["var"]. Я как бы потерял его после этой концепции. Может кто-нибудь объяснить немного о том, как этот пример работает. Как вызывается определение def __get__(self, obj, objtype): с m.x. Я был бы очень благодарен, если бы кто-нибудь мог это прояснить.

+0

Если вы используете имена параметров: 'def __get __ (self, instance, owner)' он может быть более четким. 'RevealAccess' - класс дескрипторов, а класс MyClass - это класс владельца. Имейте в виду, что классы являются объектами, поэтому 'owner' будет объектом класса MyClass'. – cdarke

ответ

2

Да, по объект автор означает экземпляр, а не класс. Различие происходит от того, где живет дескриптор; дескриптор определяется в классе, поэтому при обращении к этому дескриптору непосредственно из класса с последующим доступом к этому дескриптору выполняется экземпляр экземпляра класса.

В вашем примере m является экземпляром. Сам этот экземпляр не имеет атрибута m ('x' in m.__dict__ is False). Python также смотрит на type(m), чтобы решить этот атрибут, и type(m) здесь MyClass. 'x' in MyClass.__dict__ is True, и MyClass.__dict__['x'].__get__ существует, поэтому Python теперь знает, что этот объект является дескриптором.

Таким образом, потому что нет m.__dict__['x'], но являетсяtype(m).__dict__['x'].__get__, что метод вызывается с m и type(m) в качестве аргументов, что приводит к type(m).__dict__['x'].__get__(m, type(m)).

Если 'x' in MyClass.__dict__ верно, но MyClass.__dict__['x'].__get__ сделал не существует (так что объект не объект дескриптора), то MyClass.__dict__['x'] был бы возвращен непосредственно.

Ситуация становится более интересной, если вы попытались добавить атрибут x к экземпляру тоже. В этом случае имеет значение, если существуют MyClass.__dict__['x'].__set__ или MyClass.__dict__['x'].__delete__, что делает дескриптор данными дескриптор. Дескрипторы данных всегда выигрывают в случае галстука.Таким образом, , еслиMyClass.__dict__['x'].__get__ и по крайней мере один изMyClass.__dict__['x'].__set__ или MyClass.__dict__['x'].__delete__ существуют, это уже не имеет значения, если m.__dict__['x'] также существует. Python даже не ищет его.

Однако, если нет __set__ или __delete__ методов на объекте дескриптора класса, то m.__dict__['x'] выигрывает и возвращается. В этом случае дескриптор является обычным дескриптором без данных и теряет атрибут экземпляра.

И последнее, но не менее важное: если 'x' in type(m).__dict__ является ложным (на объекте нет объекта), возвращается m.__dict__['m']. Протокол дескриптора применяется только к объектам, найденным в классе, а не к атрибутам экземпляра.

+0

УДИВИТЕЛЬНЫЙ !! Большое вам спасибо за это. –

+0

Не могли бы вы также объяснить, что произошло бы, если x была переменной экземпляра в 'MyClass'rather, чем переменная класса? (i.e) 'if m ('x' в m .__ dict__ is True) .' –

+0

@JamesFranco: * кроме того * для' MyClass.x' существующего? –

1

Означает ли объект экземпляр класса?

Да.

Как вызывается определение def __get__(self, obj, objtype): с m.x.

Из-за только то, что документация цитируете говорит:

Для объектов, машины в object.__getattribute__(), который трансформирует b.x в type(b).__dict__['x'].__get__(b, type(b)).

object.__getattribute__ - это механизм, который реализует то, что происходит, когда вы делаете что-то вроде m.x. Таким образом, в явном виде:

m.x 
type(m).__dict__['x'].__get__(m, type(m)) 
MyClass.__dict__['x'].__get__(m, MyClass) 
RevealAccess(10, 'var "x"').__get__(m, MyClass) 

поэтому последняя строка вызывает __get__ метод RevealAccess класса.