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

Python类式包装器装饰器绑定对象方法时丢失self的行为是否合理?

装饰器返回类实例导致的self绑定问题解答

这个行为是完全符合Python方法绑定规则的预期结果,但显然不是开发者想要的效果,根源在于装饰器返回值的类型差异:

1. 正常装饰器(返回函数)的工作逻辑

decorator返回的是普通函数wrapper,当这个函数作为类方法时,Python会自动触发方法绑定机制:

  • 当通过实例three调用plus(4)时,Python会自动把three作为第一个参数(即wrapper里的my_class_self)传递进去,因此能正确输出3 + 4 = 7。

2. 有问题的装饰器(返回类实例)的问题所在

broken_decorator返回的是Wrapper类的实例——这是一个可调用对象,但Python的方法绑定逻辑只对函数生效:

  • 当通过three.plus_调用时,plus_本质是Wrapper的实例,调用它时Python不会自动把three作为参数传入。
  • 手动传入的MyClass(4)会被当作Wrapper.__call__的第一个参数my_class_self,原本的调用者three完全被忽略,因此才会输出4 + 4 = 8。

总结

如果目标是装饰类方法,应该返回函数类型的包装器,而非类实例——后者会绕过Python的方法绑定逻辑,导致self无法自动传递,出现不符合预期的调用行为。

原代码

from dataclasses import dataclass
from typing import Callable


def decorator(func: Callable[["MyClass", int], None]):
  def wrapper(my_class_self: "MyClass", y: int):
    func(my_class_self, y)
  return wrapper

def broken_decorator(func: Callable[["MyClass", int], None]):
  class Wrapper:
    def __call__(self: "Wrapper", my_class_self: "MyClass", y: int):
      func(my_class_self, y)
  return Wrapper()

@dataclass
class MyClass:
  x: int

  @decorator
  def plus(self: "MyClass", y: int) -> None:
    print(f"{self.x} + {y} = {self.x + y}")

  @broken_decorator
  def plus_(self: "MyClass", y: int) -> None:
    print(f"{self.x} + {y} = {self.x + y}")

three = MyClass(3)
three.plus(4) # 3 + 4 = 7

# with @broken_decorator
three.plus_(MyClass(4), 4) # 4 + 4 = 8, as self is the new object MyClass(4)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 23:22:23