简体   繁体   English

在python中将参数传递给装饰器

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM