考虑以下代码片段。
def print_timing(func):
import time
def wrapper(*args, **kwargs):
t1 = time.time()
res = func(*args, **kwargs)
t2 = time.time()
print '%s took %0.3f s ~ %0.0f min and %0.1f sec' % (func.func_name, t2-t1, int(t2 - t1)/60, (t2-t1) % 60 )
return res
return wrapper
@print_timing |
def foo(): |
return 'foo'
class name(object):
def __init__(self, name):
self.name = name
@print_timing
def __call__(self):
return self.name
bar = name("bar")
print bar()
这将返回:
__call__ took 0.000 s ~ 0 min and 0.0 sec
bar
对象 bar
的行为类似于名为 bar
的函数,但与装饰器 一起使用时会公开
。有没有办法更改 __call__
的内部实现细节打印计时name
对象(也许通过将合适的参数传递给 __init__
函数),使其返回
bar took 0.000 s ~ 0 min and 0.0 sec
?我想要一个解决方案,让 print_timing 装饰器继续使用普通函数。运行
print foo()
给出
foo took 0.000 s ~ 0 min and 0.0 sec
foo
最佳答案
只要您仅在方法上使用装饰器,它们就会作为第一个参数传递 self
:
def print_timing(func):
import time
def wrapper(*args, **kwargs):
t1 = time.time()
res = func(*args, **kwargs)
t2 = time.time()
funcname = func.__name__
# Special case; a "name" instance has a "name" attribute we want to use instead.
if len(args) >= 1 and isinstance(args[0], name):
funcname = args[0].name
print '%s took %0.3f s ~ %0.0f min and %0.1f sec' % (funcname, t2-t1, int(t2 - t1)/60, (t2-t1) % 60 )
return res
return wrapper
更新:包装器现在默认使用 func.__name__
,但是如果您在 name
类上使用它(如原始版本中所示)问题),它将使用实例的 name
属性。
我使用了 isinstance
测试来确定 name
属性是否存在,但您可以使用鸭子类型来代替(if hasattr(args) [0], '姓名')
); name
变量非常通用,但是当用于任意类方法时,您很可能会得到意想不到的结果。
关于python - 将装饰器与可调用对象一起使用时返回用户定义的函数名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6164291/