为什么Python不会在这个另一个描述符内部调用该函数描述符?

编程语言 2026-07-09

我有如下代码:

class Identity:
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, objtype=None):
        return self.value

    def __set__(self, obj, value):
        self.value = value


class Example:
    @Identity
    def non_method():
        pass

现在,我很惊讶的是,当我调用

>>> example = Example()
>>> example.non_method
<function Example.non_method at 0x72b74d4cb5e0>

得到的是一个函数,而不是一个绑定的方法。

在我看来,return self.valueIdentity.__get__ 中应该触发存放在 self.value 的原始 non_method 函数的描述符行为,并返回一个绑定到 Identity 对象的方法,因此 return self.value 应该大致执行 return getattr_static(self, "value").__get__(self, type(self))

起初我以为函数对象可能会检查它是否被绑定到最初定义它的类,但事实并非如此:

>>> import inspect
>>> example.non_method.__get__(inspect.getattr_static(example, "non_method"), Identity)
<bound method Example.non_method of <__main__.Identity object at 0x72b74d5b3230>>

(注意,由于我对这种行为感到神秘,这里的 example.non_method 是未绑定的函数 non_method

这是怎么回事?为什么函数的描述符不触发?

解决方案

这是因为 self.valueIdentity 中是在实例对象的 __dict__(若定义了 __slots__,则是在插槽中)进行查找,而不是在类中。

例如,考虑:

class Ten:
    def __get__(self, obj, objtype=None):
        return 10

class Example:
    ten = Ten()
>>> Example.ten
10
>>> example = Example()
>>> example.ten = Ten()
>>> example.ten
<__main__.Ten object at 0x7fcd829ebed0>

来自类和来自对象的查找是透明地交错进行的,这意味着你很难分辨到底发生了哪一种。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章