You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python方法/描述符绑定解析:无__get__时实例访问的默认行为

未实现__get__时的默认行为解析

首先明确核心逻辑:当你用@deco装饰foo.bar时,本质是执行了foo.bar = deco(foo.bar)——也就是把类foo的bar属性替换成了一个deco类的实例。

访问foo.bar的过程

直接返回类属性中存储的那个deco实例,这和你看到的输出一致:<__main__.deco object at 0x...>。

访问foo().bar的过程

当你通过foo的实例访问bar时,Python会先在该实例的__dict__(实例自身的属性字典)里查找bar,显然找不到——因为bar是定义在类上的属性。

接下来Python会去类foo的属性字典里找bar,此时找到的是那个deco实例。关键在于:这个deco实例没有实现__get__方法,不属于Python的「描述符」,所以Python不会触发任何特殊绑定逻辑,直接把类属性里的这个deco原封不动地返回给你。

这就是为什么你看到两次输出的是同一个deco对象的内存地址——不管通过类还是实例访问,拿到的都是同一个未绑定的deco实例,完全没有和foo的实例产生关联。

补充:实现__get__后的变化

当你给deco加上__get__方法后,它就变成了一个描述符。此时通过实例访问bar时,Python会自动调用__get__方法,把当前的foo实例传进去,你在__get__里返回MethodType(self, obj),相当于把deco实例和foo实例绑定在一起,最终得到的就是一个绑定方法对象,也就是你看到的<bound method foo.bar of <__main__.foo object at 0x...>>。

完整代码回顾

未实现__get__的装饰器

import functools

class deco:
    def __init__(self, main_func):
        self.main = main_func
        functools.update_wrapper(self, self.main)

    def __call__(self, obj, *args, **kwargs):
        print("decorated call")
        self.main(obj, *args, **kwargs)

class foo:
    @deco
    def bar(self):
        print("called bar")

执行输出:

>>> foo.bar
<__main__.deco object at 0x0000026BDE10F490>
>>> foo().bar
<__main__.deco object at 0x0000026BDE10F490>

实现__get__的装饰器

import functools
from types import MethodType  # 注意需要导入MethodType

class deco:
    def __init__(self, main_func):
        self.main = main_func
        functools.update_wrapper(self, self.main)

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return MethodType(self, obj)

    def __call__(self, obj, *args, **kwargs):
        print("decorated call")
        self.main(obj, *args, **kwargs)

class foo:
    @deco
    def bar(self):
        print("called bar")

执行输出:

>>> foo.bar
<__main__.deco object at 0x000001E9C721F790>
>>> foo().bar
<bound method foo.bar of <__main__.foo object at 0x000001E9C7297DD0>>

内容的提问来源于stack exchange,提问作者yankovs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:23:07