首页 新闻 会员 周边

类装饰器遇到的问题2

0
[已关闭问题] 关闭于 2026-06-22 16:07
class decorator:
    def __init__(self,func):
        wraps(func)(self)
        self.func = func
    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)
    def __get__(self, instance, owner):
        # 如果不是通过对象来调用的
        if instance is None:
            return self
        else:
            return types.MethodType(self, instance)

class cls:
    @decorator
    def method(self, x, y):
        return x + y

c = cls()
print(c.method(3, 4))  # 调用__get__后调用__call__

types.MethodType(self, instance)是不是不对,第一个参数是函数,第二个参数是对象,这里怎么是self

*Tesla*的主页 *Tesla* | 小虾三级 | 园豆:1834
提问于:2026-06-22 16:04
< >
分享
所有回答(1)
0
因为 types.MethodType 的底层是用 C 语言实现的,它在处理第一个参数时,并不严格检查它是不是一个普通的 def 函数,它只检查这个对象是不是“可调用的(Callable)”。
在这个 decorator 类中,self 实现了 __call__ 方法,所以 self 本身就是一个可调用对象。当 MethodType(self, instance) 被触发时,Python 内部会把这个 self 当作一个“类似函数的东西”来对待,并成功将它与 instance 
整个调用链条在底层是这样发生的:
  1. c.method(3, 4) 触发了绑定方法的调用。
  2. Python 自动把 c 塞进去,相当于调用了:装饰器实例.__call__(c, 3, 4)
  3. 进入 __call__ 方法内部,此时 *args 的值变成了 (c, 3, 4)
  4. 接着执行 self.func(*args, **kwargs),也就是执行了:原始方法(c, 3, 4)
  5. 原始方法 def method(self, x, y): 完美接收了这三个参数:self=c, x=3, y=4
  6. 最终返回 3 + 4 = 7

装饰器实例对象传到了 __call__ 的第一个参数 self,而 c 传到了 *args 里def __call__(self, *args, **kwargs):

decorator_instance.__call__(c, 3, 4)  ,位置参数 (c, 3, 4) 👉 全部打包进了 *args

return self.func(c, 3, 4),c 才作为第一个参数传给了原始的 method 函数,并被原始函数的 self 接收

*Tesla* | 园豆:1834 (小虾三级) | 2026-06-22 16:07
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册