从“描述符howto”文章中理解描述符示例

时间:2016-11-08 07:50:29

标签: python descriptor python-descriptors

我试图围绕描述符的概念,我最近没有成功。这个article描述符如何真正帮助,同时它也让我感到困惑。我在这里挣扎着这个例子 为什么m.x调用def __get__(self, obj, objtype):

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调用myObjects.Select(obj => obj.total).Distinct().ToList() 定义。如果有人能清除这一点,我将非常感激。

2 个答案:

答案 0 :(得分:2)

是的,通过 object ,作者意味着一个实例,而不是一个类。区别在于描述符的存在;描述符是在类上定义的,因此当直接在类上访问该描述符时,在您访问该类实例上的描述符时会遵循不同的路径。

在您的示例中,m是一个实例。该实例本身没有属性m'x' in m.__dict__False)。 Python还会查看type(m)以解析该属性,type(m)此处为MyClass'x' in MyClass.__dict__TrueMyClass.__dict__['x'].__get__存在,因此Python现在知道该对象是描述符。

因此,因为没有m.__dict__['x'],但 type(m).__dict__['x'].__get__,所以使用mtype(m)作为参数调用该方法,导致type(m).__dict__['x'].__get__(m, type(m))

如果'x' in MyClass.__dict__为真但MyClass.__dict__['x'].__get__ 存在(因此对象是描述符对象),则{{1}将直接返回。

如果您尝试将MyClass.__dict__['x']属性添加到实例,情况会变得更有趣。在这种情况下,如果存在xMyClass.__dict__['x'].__set__,则使描述符成为 data 描述符。数据描述符总是在平局的情况下获胜。所以如果 MyClass.__dict__['x'].__delete__至少有一个 MyClass.__dict__['x'].__get__MyClass.__dict__['x'].__set__存在,那么{{{{{ 1}}也存在。 Python甚至不会寻找它。

但是,如果类上的描述符对象上没有MyClass.__dict__['x'].__delete__m.__dict__['x']方法,那么__set__将获胜并返回。在这种情况下,描述符是一个常规的非数据描述符,它会丢失到实例属性。

最后但并非最不重要的是,如果__delete__为false(类上没有对象),则返回m.__dict__['x']。描述符协议仅应用于在类上找到的对象,而不应用于实例上的属性。

答案 1 :(得分: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方法。