我见过许多Python装饰器的例子:
__init__
,__get__
和__call__
)但是我从来没有见过一个可以完成上述所有操作的例子,而且我无法从对特定问题的各种答案中进行综合(例如this one,this one或{ {3}}),如何结合以上所有。
我想要的是 基于类的 装饰器,它可以装饰 方法或功能 ,和 至少需要一个附加参数 。即以下内容可行:
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()
我希望看到:
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。
答案 0 :(得分:34)
你不需要乱用描述符。在__call__()
方法中创建包装函数并返回它就足够了。标准Python函数可以始终充当方法或函数,具体取决于上下文:
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
关于使用这个装饰器时发生了什么的一些解释:
@MyDecorator("some other func!")
def some_other_function():
print "in some other function!"
第一行创建MyDecorator
的实例,并将"some other func!"
作为参数传递给__init__()
。我们称这个实例为my_decorator
。接下来,创建未修饰的函数对象 - 让它调用它bare_func
- 并将其传递给装饰器实例,从而执行my_decorator(bare_func)
。这将调用MyDecorator.__call__()
,它将创建并返回一个包装函数。最后,将此包装函数分配给名称some_other_function
。
答案 1 :(得分:11)
你错过了一个级别。
考虑代码
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
与此代码相同
class Foo(object):
def bar(self):
print "in bar!"
bar = MyDecorator("foo baby!")(bar)
因此使用MyDecorator.__init__
调用"foo baby!"
,然后使用函数MyDecorator
调用bar
对象。
也许你的意思是实现更像
的东西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
答案 2 :(得分:4)
在您的装饰器类型列表中,您错过了可能会或可能不会参数的装饰器。我认为这个例子涵盖了除“函数样式装饰器(包装函数)”之外的所有类型
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