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
相关产品推荐
相关产品推荐

