python包装函数在装饰器内部获取参数

cod*_*321 5 python decorator python-decorators

我正在尝试编写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)) + "\n"
    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)
Run Code Online (Sandbox Code Playgroud)

这与示例略有不同:

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)) + "\n"
    return wrapper

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


print my_function()

Time it took to run the function: 0.0
Run Code Online (Sandbox Code Playgroud)

似乎问题是'x'的论点.我试过给包装器*args,但它也没用.我的问题是

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

  2. 为什么我见过的所有装饰器示例都有内部函数,你能不能将装饰器作为一个函数编写?

谢谢

mVC*_*Chr 6

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

你需要将参数传递my_functionwrapper,即:

def wrapper(x):
Run Code Online (Sandbox Code Playgroud)

如果您希望它能够一般地处理更多功能,那么您必须执行以下操作:

def wrapper(*args, **kwargs):
Run Code Online (Sandbox Code Playgroud)

但是,你在装饰器中的逻辑也需要能够处理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
Run Code Online (Sandbox Code Playgroud)

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

@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
Run Code Online (Sandbox Code Playgroud)

functools.wraps将使装饰函数看起来像Python解释器的原始函数.这对于记录和调试等很有帮助,是创建装饰器时使用的最佳实践.

  • 因为装饰器本质上是这样做的:`my_function = Timing_function(my_function)`,所以即使看起来你在调用`my_function`,你实际上是在调用`wrapper`,因为`timing_function` 返回`wrapper`。所以新的`my_function` 是`wrapper`,所以`wrapper` 接收你传递给`my_function` 的args 和kwargs。 (2认同)

Pad*_*ham 5

你需要将arg添加到包装器然后添加some_function:

def timing_function(some_function):
    def wrapper(arg): 
        t1 = time.time()
        some_function(arg)
        t2 = time.time()
        return "Time it took to run: " + str((t2-t1)) + "\n"
    return wrapper
Run Code Online (Sandbox Code Playgroud)

如果你想在不同的函数上使用装饰器,可以使用*args和**kwargs,它们也适用于不带args的函数:

def timing_function(some_function):
    def wrapper(*args,**kwargs):
        t1 = time.time()
        some_function(*args,**kwargs)
        t2 = time.time()
        return "Time it took to run: " + str((t2-t1)) + "\n"
    return wrapper
Run Code Online (Sandbox Code Playgroud)

另外,如果您想为代码计时,可能会发现timeit模块非常有用,如果您安装了ipython,则可以使用timeit your_function.

为什么我见过的所有装饰器示例都有内部函数,你能不能将装饰器作为一个函数编写?

不,Python中的装饰器是一个可调用的Python对象,用于修改函数,方法或类定义.原始对象(即将要修改的对象)作为参数传递给装饰器.装饰器返回一个修改的对象,例如,经修饰的功能,这势必会在定义中使用的名称,有更多的实施例在这里