我正在尝试测量这样的装饰函数的运行时间:
import time
def timing_function(some_function):
"""Outputs the time a function takes to execute."""
def wrapper():
t1 = time.time()
some_function()
time.sleep(1)
t2 = time.time()
return "Time it took to run the function " + some_function.__name__ + " is " + str((t2-t1)) + "\n"
return wrapper
def tags(tag_name):
def tags_decorator(my_func):
"""Adds tags to a string."""
def func_wrapper(name):
return "<{0}>{1}</{0}>".format(tag_name, my_func(name))
return func_wrapper
return tags_decorator
@timing_function
@tags("p")
def get_text(name):
return "Hello "+name
然后我尝试
print get_text("World")
但是
TypeError: wrapper() takes no arguments (1 given)
有趣的是,我添加了一段代码来检查我给予wrapper()的参数是什么:
def wrapper(*args):
print "args", args
# ...
似乎得到的论点是“世界”,应该实际传递给get_text
。
反转装饰器的顺序没有帮助。有没有什么可以同时在带有和不带参数的一般装饰器中实现?
当然我可以将两个代码合并到一个包装器中,但这不是我想要的......
我正在使用python 2.6
答案 0 :(得分:1)
您需要调整wrapper()
函数以接受任意数量的参数(位置和关键字),将上的参数传递给包装函数:
def timing_function(some_function):
"""Outputs the time a function takes to execute."""
def wrapper(*args, **kw):
t1 = time.time()
some_function(*args, **kw)
time.sleep(1)
t2 = time.time()
return "Time it took to run the function " + some_function.__name__ + " is " + str((t2-t1)) + "\n"
return wrapper
*args
函数签名中的**kw
和wrapper
语法分别捕获元组和字典中的任何位置和关键字参数。 调用表达式中非常相似(相关)的语法接受序列或字典,并将那些内容作为位置或关键字参数应用于被调用的对象。这整齐地传递了从包装器到包装的任意数量的参数。
这对于tags
装饰器来说不是问题,因为它的包装器采用与包装函数完全相同的参数。这限制了装饰器只接受一个参数的函数(这也很好)。
考虑到这个装饰器忽略了包装函数的返回值;而是返回时间结果。您可能仍希望可以访问返回值(可能通过返回(return_value, timing_info)
的元组)。
演示:
>>> import time
>>> def timing_function(some_function):
... """Outputs the time a function takes to execute."""
... def wrapper(*args, **kw):
... t1 = time.time()
... some_function(*args, **kw)
... time.sleep(1)
... t2 = time.time()
... return "Time it took to run the function " + some_function.__name__ + " is " + str((t2-t1)) + "\n"
... return wrapper
...
>>> def tags(tag_name):
... def tags_decorator(my_func):
... """Adds tags to a string."""
... def func_wrapper(name):
... return "<{0}>{1}</{0}>".format(tag_name, my_func(name))
... return func_wrapper
... return tags_decorator
...
>>> @timing_function
... @tags("p")
... def get_text(name):
... return "Hello "+name
...
>>> get_text('World')
'Time it took to run the function func_wrapper is 1.00514888763\n'