具有旧式类的Python描述符

ale*_*sel 6 python class descriptor

我试图谷歌一些关于它的东西.为什么非数据描述符适用于旧式类?

Docs说它们不应该:
" 请注意,描述符只能用于新的样式对象或类(子类object()或子类type()). "

class Descriptor(object):
    def __init__(self):
        self.x = 1

    def __get__(self, obj, cls=None):
        return self.x


class A:
    x = Descriptor()

a = A()
a.x

>>> 1
Run Code Online (Sandbox Code Playgroud)

谢谢.

ice*_*ime 4

您质疑文档是正确的。我尝试通过CPython 源代码寻找解释,但请注意:我不是专家。

根据我的理解,属性查找和描述__get__符调用发生在instance_getattr2(选定的摘录)中:

v = class_lookup(inst->in_class, name, &klass);
if (v != NULL) {
    f = TP_DESCR_GET(v->ob_type);
    if (f != NULL) {
        PyObject *w = f(v, (PyObject *)inst, (PyObject *)(inst->in_class));
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,要么我遗漏了一些东西,要么实现中没有任何内容需要新样式的对象(这与文档相矛盾)。

作为记录,我尝试重新编译 Python 以限制对新样式类对象的描述符调用,但它实际上带来了巨大的混乱。我在这个过程中了解到,类方法本身是作为描述符实现的:这是用于根据使用情况返回绑定或未绑定方法对象的机制。例如:

>>> class A:
...     def foo():
...         pass
...
>>> A.foo.__get__(None, A)
<unbound method A.foo>
>>> A.foo.__get__(A(), A)
<bound method A.foo of <__main__.A instance at 0x000000000229CC48>>
Run Code Online (Sandbox Code Playgroud)

因此,阻止对旧式对象或类的属性的描述符调用似乎也会阻止对它们的方法调用,至少在 CPython 实现中是这样。

再说一次,我不是专家,这是我第一次深入研究 Python 实现,所以我很可能是错的。我已经提交了一个问题来试图澄清这一点。