[英]Python Class Based Decorator with parameters that can decorate a method or a function
I've seen many examples of Python decorators that are:我见过很多 Python 装饰器的例子,它们是:
__init__
, __get__
, and __call__
)__init__
、 __get__
和__call__
)But I've never seen a single example which can do all of the above, and I'm having trouble synthesizing from various answers to specific questions (such as this one , this one , or this one (which has one of the best answers I've ever seen on SO) ), how to combine all of the above.但是我从未见过可以完成上述所有操作的单个示例,而且我无法从特定问题的各种答案(例如this one 、 this one或this one (具有最佳答案之一)进行综合)我曾经在 SO) ) 上看到过如何将上述所有内容结合起来。
What I want is a class-based decorator which can decorate either a method or a function , and that takes at least one additional parameter .我想要的是一个基于类的装饰器,它可以装饰一个方法或一个函数,并且至少需要一个额外的参数。 Ie so that the following would work:
即,以便以下工作:
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()
And I would expect to see:我希望看到:
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!
Edit: if it matters, I'm using Python 2.7.编辑:如果重要的话,我使用的是 Python 2.7。
You don't need to mess around with descriptors.你不需要弄乱描述符。 It's enough to create a wrapper function inside the
__call__()
method and return it.在
__call__()
方法中创建一个包装函数并返回它就足够了。 Standard Python functions can always act as either a method or a function, depending on context:标准 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
result = fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % self.arg
return result
return decorated
A bit of explanation about what's going on when this decorator is used like this:关于当这个装饰器这样使用时发生了什么的一些解释:
@MyDecorator("some other func!")
def some_other_function():
print "in some other function!"
The first line creates an instance of MyDecorator
and passes "some other func!"
第一行创建了一个
MyDecorator
的实例并传递了"some other func!"
as an argument to __init__()
.作为
__init__()
的参数。 Let's call this instance my_decorator
.让我们称这个实例为
my_decorator
。 Next, the undecorated function object -- let's call it bare_func
-- is created and passed to the decorator instance, so my_decorator(bare_func)
is executed.接下来,未装饰的函数对象——让我们称之为
bare_func
被创建并传递给装饰器实例,因此my_decorator(bare_func)
被执行。 This will invoke MyDecorator.__call__()
, which will create and return a wrapper function.这将调用
MyDecorator.__call__()
,它将创建并返回一个包装函数。 Finally this wrapper function is assigned to the name some_other_function
.最后这个包装函数被分配给名称
some_other_function
。
You're missing a level.你缺少一个级别。
Consider the code考虑代码
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
It is identical to this code它与此代码相同
class Foo(object):
def bar(self):
print "in bar!"
bar = MyDecorator("foo baby!")(bar)
So MyDecorator.__init__
gets called with "foo baby!"
所以
MyDecorator.__init__
被调用为"foo baby!"
and then the MyDecorator
object gets called with the function bar
.然后使用函数
bar
调用MyDecorator
对象。
Perhaps you mean to implement something more like也许你的意思是实现更像
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
In your list of types of decorators, you missed decorators that may or may not take arguments.在您的装饰器类型列表中,您错过了可能带参数也可能不带参数的装饰器。 I think this example covers all your types except "function style decorators (wrapping a function)"
我认为这个例子涵盖了除“函数风格装饰器(包装函数)”之外的所有类型
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.