在修饰器中接受参数的Python包装函数

2022-04-07 00:00:00 python python-decorators decorator

问题描述

我正在尝试编写Python装饰符,但我在理解内部包装器如何接受参数时遇到了问题。我有:

import time

def timing_function(some_function):
    def wrapper():
        t1 = time.time()
        some_function()
        t2 = time.time()
        return "Time it took to run: " + str((t2-t1)) + "
"
    return wrapper

@timing_function
def my_function(x):
    return x * x

my_function(6)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-fe2786a2753c> in <module>()
----> 1 my_function(6)

TypeError: wrapper() takes no arguments (1 given)

与示例略有不同:

import time

def timing_function(some_function):

    """
    Outputs the time a function takes
    to execute.
    """

    def wrapper():
        t1 = time.time()
        some_function()
        t2 = time.time()
        return "Time it took to run the function: " + str((t2-t1)) + "
"
    return wrapper

@timing_function
def my_function():
    num_list = []
    for x in (range(0,10000)):
        num_list.append(x)
    return "
Sum of all the numbers: " +str((sum(num_list)))


print my_function()

Time it took to run the function: 0.0

似乎问题出在‘x’参数上。我尝试给包装器*args,但也不起作用。我的问题是

  1. 在这个简单的包装器中允许参数的正确方式是什么?谢谢您

  2. 为什么我看到的所有修饰器示例都有内部函数,难道不能将修饰器作为一个函数来编写吗?

谢谢


解决方案

  1. 在这个简单的包装器中允许参数的正确方式是什么?谢谢您

您需要将参数从my_function传递到wrapper,即:

def wrapper(x):

如果您希望它能够处理更多的通用功能,则必须执行以下操作:

def wrapper(*args, **kwargs):

但是,装饰符中的逻辑还需要能够处理一般的argskwargs

  1. 为什么我看到的所有修饰器示例都有内部函数,难道不能把修饰器写成一个函数吗?

因为修饰符是一个函数,它接受一个函数作为参数,并返回一个作为原始函数的包装器执行的函数。事实上,装饰符通常被编写为三个函数:

from functools import wraps

def somedec(somearg, someopt=None):
    def somedec_outer(fn):
        @wraps(fn)
        def somedec_inner(*args, **kwargs):
            # do stuff with somearg, someopt, args and kwargs
            response = fn(*args, **kwargs)
            return response
        return somedec_inner
    return somedec_outer

为什么要这样做?您可以根据要修饰的函数类型,或者可能根据修饰符的不同行为方式,将一些信息传递给修饰符。

@somedec(30.0, 'foobarbaz')
def somefn(a, b, c):
    return a + b + c

@somedec(15.0, 'quxjinzop')
def otherfn(d, e, f):
    return d - e - f

functools.wraps将使修饰后的函数在Python解释器中看起来像原始函数。这对日志记录和调试等很有帮助,并且是创建修饰符时使用的最佳实践。

相关文章