[英]Passing a parameter to the decorator in python
Why is this decorator with a parameter not working?为什么这个带参数的装饰器不起作用?
def decAny( f0 ):
def wrapper( s0 ):
return "<%s> %s </%s>" % ( any, f0(), any )
return wrapper
@decAny( 'xxx' )
def test2():
return 'test1XML'
print( test2() )
always gives me an error saying "str is not callable" it is trying to execute the return string inside the wrapper() instead of processing it and return the result string总是给我一个错误,说“str 不可调用”它试图在 wrapper() 中执行返回字符串而不是处理它并返回结果字符串
Decorators are functions that return functions.装饰器是返回函数的函数。 When "passing a parameter to the decorator" what you are actually doing is calling a function that returns a decorator.当“将参数传递给装饰器”时,您实际上是在调用一个返回装饰器的函数。 So decAny()
should be a function that returns a function that returns a function.所以decAny()
应该是一个返回函数的函数,该函数返回一个函数。
It would look something like this:它看起来像这样:
import functools
def decAny(tag):
def dec(f0):
@functools.wraps(f0)
def wrapper(*args, **kwargs):
return "<%s> %s </%s>" % (tag, f0(*args, **kwargs), tag)
return wrapper
return dec
@decAny( 'xxx' )
def test2():
return 'test1XML'
Example:例子:
>>> print(test2())
<xxx> test1XML </xxx>
Note that in addition to fixing the specific problem you were hitting I also improved your code a bit by adding *args
and **kwargs
as arguments to the wrapped function and passing them on to the f0
call inside of the decorator.请注意,除了解决您遇到的特定问题之外,我还通过添加*args
和**kwargs
作为包装函数的参数并将它们传递给装饰器内部的f0
调用来稍微改进您的代码。 This makes it so you can decorate a function that accepts any number of positional or named arguments and it will still work correctly.这使得你可以装饰一个接受任意数量的位置或命名参数的函数,它仍然可以正常工作。
You can read up about functools.wraps()
here:您可以在此处阅读有关functools.wraps()
信息:
http://docs.python.org/2/library/functools.html#functools.wraps http://docs.python.org/2/library/functools.html#functools.wraps
There is a good sample from "Mark Lutz - Learning Python" book: “Mark Lutz - Learning Python”一书中有一个很好的示例:
def timer(label=''):
def decorator(func):
def onCall(*args): # Multilevel state retention:
... # args passed to function
func(*args) # func retained in enclosing scope
print(label, ... # label retained in enclosing scope
return onCall
return decorator # Returns the actual decorator
@timer('==>') # Like listcomp = timer('==>')(listcomp)
def listcomp(N): ... # listcomp is rebound to new onCall
listcomp(...) # Really calls onCall
there is another to implement decorator using class and you can also pass arguments to the decorator itself还有另一个使用类来实现装饰器,您也可以将参数传递给装饰器本身
here is an example of a logger helper decorator, which you can pass the function scope and the returned value when it fails这是记录器辅助装饰器的示例,您可以在失败时传递函数范围和返回值
import logging
class LoggerHelper(object):
def __init__(self, scope, ret=False):
self.scope = scope
self.ret = ret
def __call__(self, original_function):
def inner_func(*args, **kwargs):
try:
logging.info(f"*** {self.scope} {original_function.__name__} Excuting ***")
return original_function(*args, **kwargs)
logging.info(f"*** {self.scope} {original_function.__name__} Executed Successfully ***")
except Exception as e:
logging.error(f"*** {self.scope} {original_function.__name__} Error: {str(e)} ***")
return self.ret
return inner_func
and when you use it, you can easily track where the exception was raised并且当您使用它时,您可以轻松跟踪引发异常的位置
class Example:
@LoggerHelper("Example", ret=False)
def method:
print(success)
return True
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.