【问题标题】:Python descriptors with old-style classes带有老式类的 Python 描述符
【发布时间】:2013-05-23 10:50:21
【问题描述】:

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

文档说他们不应该:
Note that descriptors are only invoked for new style objects or classes (ones that subclass object() or 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

谢谢。

【问题讨论】:

  • 因为'Descriptor'是一个新式类。

标签: python class descriptor


【解决方案1】:

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

据我了解,属性查找和描述符__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));
    }
}

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

作为记录,我尝试重新编译 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>>

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

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

【讨论】:

  • 感谢调查,真的很有帮助。
  • 我在 CPython 调试会话后编辑了我的答案:我涉及的函数错误,但结果保持不变。
  • 在 Python 中,所有函数(包括方法)都是非数据描述符。所以他们应该像你说的那样行事。
  • 但我还有一个问题。如果 Descriptor 是老式类,为什么 __get__ 不起作用?我认为如果旧式(或新式)类的属性或方法是object 的子实例(所有函数都是)​​,解释器试图执行__get__
  • 请注意,在 python3 中,未绑定的方法已经消失。它们只是类的函数属性。 @alexvassel 我相信限制不在于使用描述符的类(在您的示例中为A),而在于实现描述符的类(Descriptor)。如果Descriptor 是一个老式类,那么__get/set/del__ not 被视为特殊方法,因此它们不会被调用。当Descriptor 类继承object 时,那些方法被认为是特殊的
猜你喜欢
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
  • 2015-08-28
  • 2011-06-22
  • 2013-09-05
  • 1970-01-01
  • 2016-02-23
  • 2018-09-06
相关资源
最近更新 更多