Python Class Based Decorator with parameters that can decorate a method or a function
我见过很多关于python装饰的例子:
- 函数样式装饰器(包装函数)
- 类风格装饰(实现
__init__ 、__get__ 和__call__ ) - 不接受参数的修饰符
- 接受参数的修饰符
- "方法友好"的装饰器(即可以在类中装饰方法)
- "功能友好"的装饰师(可以装饰简单的功能
- 既可以修饰方法又可以修饰函数的修饰器
小精灵
但是我从来没有见过一个能完成上述所有工作的例子,而且我很难从各种答案中综合出具体的问题(比如这个,这个,或者这个(我见过的最好的答案之一)),如何综合上述所有问题。
我想要的是一个基于类的修饰器,它可以修饰一个方法或函数,并且至少需要一个附加参数。也就是说,以下内容可以工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class MyDecorator(object): def __init__(self, fn, argument): self.fn = fn self.arg = argument def __get__(self, ....): # voodoo magic for handling distinction between method and function here def __call__(self, *args, *kwargs): print"In my decorator before call, with arg %s" % self.arg self.fn(*args, **kwargs) print"In my decorator after call, with arg %s" % self.arg class Foo(object): @MyDecorator("foo baby!") def bar(self): print"in bar!" @MyDecorator("some other func!") def some_other_function(): print"in some other function!" some_other_function() Foo().bar() |
我希望看到:
1 2 3 4 5 6 | In my decorator before call, with arg some other func! in some other function! In my decorator after call, with arg some other func! In my decorator before call, with arg foo baby! in bar! In my decorator after call, with arg foo baby! |
号
编辑:如果重要的话,我使用的是python 2.7。
你不需要乱弄描述符。在
1 2 3 4 5 6 7 8 9 10 11 | class MyDecorator(object): def __init__(self, argument): self.arg = argument def __call__(self, fn): @functools.wraps(fn) def decorated(*args, **kwargs): print"In my decorator before call, with arg %s" % self.arg fn(*args, **kwargs) print"In my decorator after call, with arg %s" % self.arg return decorated |
解释一下当这个装饰器像这样使用时会发生什么:
1 2 3 | @MyDecorator("some other func!") def some_other_function(): print"in some other function!" |
号
第一行创建
你错过了一个关卡。
考虑一下代码
1 2 3 4 | class Foo(object): @MyDecorator("foo baby!") def bar(self): print"in bar!" |
与此代码相同
1 2 3 4 | class Foo(object): def bar(self): print"in bar!" bar = MyDecorator("foo baby!")(bar) |
。
所以用
也许你的意思是实现一些更像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import functools def MyDecorator(argument): class _MyDecorator(object): def __init__(self, fn): self.fn = fn def __get__(self, obj, type=None): return functools.partial(self, obj) def __call__(self, *args, **kwargs): print"In my decorator before call, with arg %s" % argument self.fn(*args, **kwargs) print"In my decorator after call, with arg %s" % argument return _MyDecorator |
在修饰符类型的列表中,缺少可能接受参数或不接受参数的修饰符。我认为这个例子涵盖了除"函数样式装饰器(包装函数)"之外的所有类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class MyDecorator(object): def __init__(self, argument): if hasattr('argument', '__call__'): self.fn = argument self.argument = 'default foo baby' else: self.argument = argument def __get__(self, obj, type=None): return functools.partial(self, obj) def __call__(self, *args, **kwargs): if not hasattr(self, 'fn'): self.fn = args[0] return self print"In my decorator before call, with arg %s" % self.argument self.fn(*args, **kwargs) print"In my decorator after call, with arg %s" % self.argument class Foo(object): @MyDecorator("foo baby!") def bar(self): print"in bar!" class Bar(object): @MyDecorator def bar(self): print"in bar!" @MyDecorator def add(a, b): print a + b |
。