为什么这个装饰器的参数不起作用?
def decAny( f0 ):
def wrapper( s0 ):
return "<%s> %s </%s>" % ( any, f0(), any )
return wrapper
@decAny( 'xxx' )
def test2():
return 'test1XML'
print( test2() )
总是给我一个错误,说“str不可调用” 它试图在包装器()内执行返回字符串 而不是处理它并返回结果字符串
答案 0 :(得分:16)
装饰器是返回函数的函数。当“将参数传递给装饰器”时,您实际在做的是调用返回装饰器的函数。所以decAny()
应该是一个返回函数的函数。
它看起来像这样:
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'
示例:
>>> print(test2())
<xxx> test1XML </xxx>
请注意,除了修复您遇到的特定问题之外,我还通过将*args
和**kwargs
作为参数添加到包装函数并将它们传递给{{1}来改进您的代码。调用装饰器内部。这使得你可以装饰一个接受任意数量的位置或命名参数的函数,它仍然可以正常工作。
您可以在此处阅读f0
:
http://docs.python.org/2/library/functools.html#functools.wraps
答案 1 :(得分:1)
来自&#34; Mark Lutz - 学习Python&#34;书:
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
答案 2 :(得分:0)
还有另一个使用类来实现装饰器,您也可以将参数传递给装饰器本身
这里是一个记录器辅助装饰器的例子,你可以在它失败时传递函数作用域和返回值
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
并且当您使用它时,您可以轻松跟踪异常发生的位置
class Example:
@LoggerHelper("Example", ret=False)
def method:
print(success)
return True