【发布时间】:2020-01-11 09:12:20
【问题描述】:
我正在尝试为方法创建一个包装器。
装饰器本身被实现为一个覆盖__call__ 方法的类。
这适用于装饰函数,但如果以这种方式装饰方法,self 不会绑定到装饰函数。
以下是一个最小示例:
import functools
class Wrapper:
def __init__(self, func) -> None:
super().__init__()
self.__func = func
functools.update_wrapper(self, func)
def __call__(self, *args, **kwargs):
print("PreBar")
result = self.__func(*args, **kwargs)
print("PostBar")
return result
def MyDecorator(func):
return Wrapper(func)
class Foo:
baz = "Baz"
@MyDecorator
def bar(self):
print(self.baz)
return self.baz
if __name__ == '__main__':
foo = Foo()
print(foo.bar)
print(f"Result of foo.bar(): {foo.bar()}")
print(Foo.bar)
print(f"Result of Foo.bar(foo): {Foo.bar(foo)}")
这会产生以下错误,这意味着 self 不会像普通方法一样自动传递给 __call__ 调用:
Traceback (most recent call last):
File "/mypath/test.py", line 35, in <module>
print(f"Result of foo.bar(): {foo.bar()}")
File "/mypath/test.py", line 14, in __call__
result = self.__func(*args, **kwargs)
TypeError: bar() missing 1 required positional argument: 'self'
问题:返回的可调用包装对象如何绑定到self?
将对象包装在函数中以让 python 进行绑定是一种选择,但在我的情况下不是这样,因为需要实际的对象。
How can I decorate an instance method with a decorator class? 的问题类似于我想要实现的目标。如果只需要绑定,那里提供的解决方案就可以工作。我需要的是,访问属性时返回的对象实例是Wrapper 类型,而不是functools.partial 类型。
second answer to that question 也不起作用,因为__get__ 返回的实例是method 类型而不是Wrapper。
【问题讨论】:
-
MyDecorator的意义何在?你可以直接用Wrapper装饰bar。 -
@chepner 你是对的。对于我的最小示例,我可以省略该函数。原代码使用了一个 MyDecorator 类,因为装饰器带有参数。
标签: python