Python 从“理解描述符示例”;“如何”的描述符;文章

Python 从“理解描述符示例”;“如何”的描述符;文章,python,descriptor,python-descriptors,Python,Descriptor,Python Descriptors,我正试图把我的头脑围绕在描述符的概念上,但我最近没有成功。这一描述对我有很大帮助,同时也让我感到困惑。我在这里与这个例子作斗争 关于为什么m.x调用def\uu-get\uu(self、obj、objtype): 我相信我之所以在这方面苦苦挣扎,是因为我对文章中的以下陈述感到困惑 调用的细节取决于obj是对象还是对象 班级。对于对象,机器位于对象中。\uuu getattribute\uuuu() 它将b.x转换为类型(b)。\uuuuu dict\uuuuu['x']。\uuuu get\uu

我正试图把我的头脑围绕在描述符的概念上,但我最近没有成功。这一描述对我有很大帮助,同时也让我感到困惑。我在这里与这个例子作斗争 关于为什么
m.x
调用
def\uu-get\uu(self、obj、objtype):

我相信我之所以在这方面苦苦挣扎,是因为我对文章中的以下陈述感到困惑

调用的细节取决于obj是对象还是对象 班级。对于对象,机器位于
对象中。\uuu getattribute\uuuu()
它将
b.x
转换为
类型(b)。\uuuuu dict\uuuuu['x']。\uuuu get\uuuuuu(b,类型(b))
。 该实现通过提供数据的优先级链工作 描述符优先于实例变量,实例变量 优先级高于非数据描述符,并将最低优先级分配给
\uuuu getattr\uuuuu()
如果提供

我不确定作者这里所说的对象或类是什么意思。对象是否表示类的实例?我理解,当我们执行
instance.var
时,python会在内部执行
实例。在那之后我有点失去了它。有人能解释一下这个例子是如何工作的吗。定义
def\uu get\uu(self、obj、objtype):
是如何用
m.x
调用的。如果有人能澄清这一点,我将不胜感激。

是的,作者所说的对象是一个实例,而不是一个类。区别来自描述者居住的地方;描述符是在类上定义的,因此当直接在类上访问该描述符时,将遵循与在类实例上访问该描述符时不同的路径

在您的示例中,
m
是一个实例。该实例本身没有属性
m
(m中的
'x'。\uu dict\uuu
False
)。Python还查看
type(m)
来解析该属性,而
type(m)
这里是
MyClass
<代码>MyClass中的“x”。\uuuu dict\uuuu
True
,并且
MyClass.\uu dict\uuuu['x']。\uu get\uuuu
存在,因此Python现在知道该对象是一个描述符

因此,因为没有
m.\uuu dict\uuuuuuuu['x']
,但是有一个
type(m)。\uu dict\uuuuuu['x'].\uu get\uuuuuuuuuu
,这个方法是用
m
type(m)
作为参数调用的,导致
type(m)。\uu dict\uuuuuuuuuuuuuuuuu['x']

如果MyClass中的
'x.\uuuuu dict\uuuuu
为true,但
MyClass.\uuuu dict\uuuuuu['x'].\uuu get\uuuuuuuu
不存在(因此该对象不是描述符对象),则将直接返回
MyClass.\uuuu dict\uuuuuu['x']

如果您尝试将
x
属性也添加到实例中,情况会变得更有趣。在这种情况下,如果存在
MyClass.\uuuuu dict.\uuuuu['x']。\uuuu set.\uuuu
MyClass.\uuuu dict.\uuuu['x']。\uuuu delete.\uuuu
则很重要,使描述符成为数据描述符。数据描述符总是在平局中获胜。因此,如果
MyClass.\uuu dict.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。Python甚至不会去寻找它

但是,如果类上的描述符对象上没有
\uuuuuu set\uuuuuuuu
\uuuu delete\uuuuuuuuuuu
方法,则
m.\uuuuu dict\uuuuuuu['x']
获胜并返回。在这种情况下,描述符是一个常规的非数据描述符,它会丢失给instance属性

最后但并非最不重要的一点是,如果类型(m)中的
'x.\uuu dict\uuu
为false(类上没有对象),则返回
m.\uu dict\uu['m']
。描述符协议仅应用于类上的对象,而不应用于实例上的属性。

是的,按对象而言,作者指的是实例,而不是类。区别来自描述者居住的地方;描述符是在类上定义的,因此当直接在类上访问该描述符时,将遵循与在类实例上访问该描述符时不同的路径

在您的示例中,
m
是一个实例。该实例本身没有属性
m
(m中的
'x'。\uu dict\uuu
False
)。Python还查看
type(m)
来解析该属性,而
type(m)
这里是
MyClass
<代码>MyClass中的“x”。\uuuu dict\uuuu
True
,并且
MyClass.\uu dict\uuuu['x']。\uu get\uuuu
存在,因此Python现在知道该对象是一个描述符

因此,因为没有
m.\uuu dict\uuuuuuuu['x']
,但是有一个
type(m)。\uu dict\uuuuuu['x'].\uu get\uuuuuuuuuu
,这个方法是用
m
type(m)
作为参数调用的,导致
type(m)。\uu dict\uuuuuuuuuuuuuuuuu['x']

如果MyClass中的
'x.\uuuuu dict\uuuuu
为true,但
MyClass.\uuuu dict\uuuuuu['x'].\uuu get\uuuuuuuu
不存在(因此该对象不是描述符对象),则将直接返回
MyClass.\uuuu dict\uuuuuu['x']

如果您尝试将
x
属性也添加到实例中,情况会变得更有趣。在这种情况下,如果存在
MyClass.\uuuuu dict.\uuuuu['x']。\uuuu set.\uuuu
MyClass.\uuuu dict.\uuuu['x']。\uuuu delete.\uuuu
则很重要,使描述符成为数据描述符。数据描述符总是在平局中获胜。因此,如果
MyClass.\uuu dict.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。Python甚至不会去寻找它

但是,如果类上的描述符对象上没有
\uuuu set\uuu
\uu delete\uuuu
方法,则
m
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
m.x
type(m).__dict__['x'].__get__(m, type(m))
MyClass.__dict__['x'].__get__(m, MyClass)
RevealAccess(10, 'var "x"').__get__(m, MyClass)