7

为什么这个带参数的装饰器不起作用?

def decAny( f0 ):
    def wrapper( s0 ):
        return "<%s> %s </%s>" % ( any, f0(), any )
    return wrapper

@decAny( 'xxx' )
def test2():
    return 'test1XML'

print( test2() )

总是给我一个错误说“str is not callable”它试图在 wrapper() 中执行返回字符串而不是处理它并返回结果字符串

4

3 回答 3

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作为参数添加到包装函数并将它们传递给f0装饰器内部的调用,对您的代码进行了一些改进。这使得你可以装饰一个接受任意数量的位置或命名参数的函数,它仍然可以正常工作。

你可以在这里阅读:http functools.wraps():
//docs.python.org/2/library/functools.html#functools.wraps

于 2013-03-25T21:11:53.737 回答
1

“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
于 2014-03-21T15:42:25.097 回答
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
于 2021-03-12T14:23:24.260 回答