我正在尝试编写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)
与示例略有不同:
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
问题似乎是&#39; x&#39;论点。我试过给包装器* args,但它也没用。我的问题是
在这个简单的包装器中允许参数的正确方法是什么?谢谢
为什么我看到的所有装饰器示例都有内部函数,你能不能将装饰器作为一个函数编写?
谢谢
答案 0 :(得分:6)
您需要将参数从my_function
传递给wrapper
,即:
def wrapper(x):
如果您希望它能够一般地处理更多功能,那么您必须执行以下操作:
def wrapper(*args, **kwargs):
但是,装饰器中的逻辑也需要能够一般地处理args
和kwargs
。
因为装饰器是一个函数,它将函数作为参数并返回一个作为原始函数的包装器执行的函数。实际上,装饰器通常被编写为三个函数:
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解释器的原始函数。这对于记录和调试等很有帮助,是创建装饰器时使用的最佳实践。
答案 1 :(得分: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
如果你想在不同的函数上使用装饰器,可以使用* 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
在旁注中,如果您想为代码计时,可能会发现timeit模块很有用,如果您安装了ipython,则只需使用timeit your_function
。
为什么我见过的所有装饰器示例都有内部函数,你能不能将装饰器作为一个函数编写?
不, Python中的装饰器是一个可调用的Python对象,用于修改函数,方法或类定义。原始对象(即将要修改的对象)作为参数传递给装饰器。装饰器返回修改后的对象,例如修改后的函数绑定到定义中使用的名称,还有更多示例here