1

我试图围绕描述符的概念来思考,但最近我没有成功。这篇关于如何描述的文章确实有帮助,同时也让我感到困惑。我在这个例子中苦苦挣扎,为什么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.xtype(b).__dict__['x'].__get__(b, type(b))。该实现通过优先链进行工作,该优先链赋予数据描述符优先于实例变量,实例变量优先于非数据描述符, __getattr__()如果提供,则分配最低优先级

我不确定作者在这里所说的对象或类是什么意思。对象是否意味着类的实例?我知道,当我们在instance.var内部执行 python时instance.__dict__["var"],如果未找到,则它会执行class.__dict__["var"]。在那个概念之后,我有点失去了它。谁能解释一下这个例子是如何工作的。定义是如何def __get__(self, obj, objtype):被调用的m.x。如果有人能解决这个问题,我将不胜感激。

4

2 回答 2

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__调用该方法,导致。mtype(m)type(m).__dict__['x'].__get__(m, type(m))

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

如果您也尝试将x属性添加到实例,情况会变得更有趣。在这种情况下,是否或存在使描述符成为数据描述符很重要。在平局的情况下,数据描述符总是获胜。因此,如果并且至少其中一个or存在,那么它是否也存在不再重要。Python 甚至不会寻找它。MyClass.__dict__['x'].__set__MyClass.__dict__['x'].__delete__ MyClass.__dict__['x'].__get__ MyClass.__dict__['x'].__set__MyClass.__dict__['x'].__delete__m.__dict__['x']

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

最后但同样重要的是,如果'x' in type(m).__dict__为假(类上没有对象),则m.__dict__['m']返回。描述符协议仅适用于在类中找到的对象,而不适用于实例上的属性。

于 2016-11-08T07:57:39.160 回答
1

对象是否意味着类的实例?

是的。

定义是如何def __get__(self, obj, objtype):被调用的m.x

由于您引用的文档所说的内容:

对于物体来说,机器在object.__getattribute__()其中转化b.xtype(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

于 2016-11-08T07:58:58.653 回答