如何将参数传递给decorator,在那里进行处理,然后转发到修饰函数?

2024-10-01 09:38:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近决定学习Python装饰器,并学习了this howto。尤其是“将参数传递给decorators”部分下的示例。我要做的是(1)decorator函数应该接受一些参数(degarg),(2)处理它们,以及(3)使用参数调用修饰函数(funarg)。我知道如何给decorator提供参数,但是我还没有看到任何例子,其中decorated函数的参数只在decorator中可用。当我调用decorated函数时,我完全不确定应该使用什么参数,因为它的参数将在decorator函数中计算。下面是一个基于上述操作方法的示例:

def dec(decarg):
    def _dec(fun):
        funarg = decarg + 7
        def _fun(funarg):
            return fun(funarg)
        return _fun
    return _dec

def main(mainarg):
    decarg = mainarg + 2
    @dec(decarg)
    def fun1(funarg):
        return funarg + 3
    return fun1(decarg)

main(1)

它返回6,而我预期是13。我希望参数在main()中递增2,在_dec()中增加7,这将把这个变量传递给修饰函数,后者向它添加3。在

之后,我阅读了this和{a3}howtos,并使用他们的方法创建了一个与我想象的一样的示例:

^{pr2}$

所以现在我的问题是:如何对第一种表示法做同样的处理,其中decorator不是一个类,而是一个函数?请您澄清一下,它是如何工作的,哪些参数和何时被传递给__init__(),以及给装饰器的__call__()方法什么?在


Tags: 函数示例参数returnmaindef装饰decorator
2条回答

原因是在考虑了decorator如何转换函数以及函数本身就是Python中的对象之后。在

我们从后者开始。在

函数是对象:

当我们考虑函数名后两对括号的含义时,这是立即的。考虑这个简单的例子(Python3):

def func(x):
    def func2(y):
        return x + y + 1
    return func2

result = func(5)(10)
print(result)  # 15

这里“func”返回一个函数对象“func2”,因此您可以使用:

^{pr2}$

您可以将此视为先调用

func(5)

并将“(10)”应用于结果对象,即函数!所以你有:

func2(10)

现在既然定义了“x”和“y”,那么“func2”可以将最终值返回到“result”。在

记住,这是可能的,因为函数本身就是对象,而且“func”返回的是函数对象

func2

并且不是它的结果(它不是单独调用函数)

func2()

简言之,这意味着对于包装函数,第二组参数用于内部函数(如果包装器返回内部函数对象)。在

装饰者:

在您的示例中,“main”在最后一行中调用“fun1”

return fun1(decarg)

因为装修工

@dec(decarg)

实际上,你可以把“fun1”想象成:

fun1 = dec(decarg)(fun1)

因此,“main”中的最后一行相当于:

return dec(decarg)(fun1)(decarg)

根据前面的解释,找到问题应该很简单!在

  • dec(decarg)被执行并返回一个“_dec”函数对象;注意这个“decarg”是在第一个括号中传递的对象,因此在decorator中也是这样。在
  • _dec(fun1)执行并返回一个“\u fun”函数对象。在
  • _fun(decarg)执行并使用return语句调用fun1(decargs),这将在fun1(3)中正确转换,这是您得到的结果;请注意,这个“decarg”是在第三个括号中传递的,因此当您在main中调用“fun1”时也是如此。在

你不能得到13,因为你没有调用“fun1”的结果

funarg = decarg + 7

作为参数,而是使用从main传递给“\u fun”的“degarg”作为位置参数(funarg=decarg)来调用它。在

不管怎样,我必须感谢您提出这个问题,因为我正在寻找一种简单的方法,只在调用函数时才将参数传递给decorator,这非常有效。在

下面是另一个可能有帮助的示例:

from functools import wraps

def add(addend):
    def decorator(func):
        @wraps(func)
        def wrapper(p1, p2=101):
            for v in func(p1, p2):
                yield v + addend
        return wrapper
    return decorator


def mul(multiplier):
    def decorator(func):
        @wraps(func)
        def wrapper(p1, p2=101):
            for v in func(p1, p2):
                yield v * multiplier
        return wrapper
    return decorator


def super_gen(p1, p2=101, a=0, m=1):
    @add(a)
    @mul(m)
    def gen(p1, p2=101):
        for x in range(p1, p2):
            yield x
    return gen(p1, p2)

好的,这里有一个简单的解释:

一个简单的装饰器(没有参数)是一个函数,它接受一个函数作为参数,并返回另一个函数来代替原来的函数

接受参数的decorator是一个接受该参数并返回一个简单decorator的函数

在这里,您可以构建一个简单的decorator,将7添加到修饰函数的参数中:

def add7(func):
    '''takes a func and returns a decorated func adding 7 to its parameter'''
    def resul(x):
        return func(x + 7)
    return resul

您可以这样使用它:

^{pr2}$

它按预期返回13。在

但您可以轻松地构建一个参数化的decorator,它将添加一个任意值,但添加一个用于处理参数的级别:

def adder(incr):
    '''Process the parameter (the increment) and returns a simple decorator'''
    def innerdec(func):
        '''Decorator that takes a function and returns a decorated one
that will add the passed increment to its parameter'''
        def resul(val):
            return func(val + incr)
        return resul
    return innerdec

然后你就可以那样用了

 def main(mainarg):
    decarg = mainarg + 2
    @adder(7)
    def fun1(funarg):
        return funarg + 3
    return fun1(decarg)

main(1)

仍然返回13

相关问题 更多 >