2

考虑以下代码片段。

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__print_timingname__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
4

3 回答 3

1

不。装饰器在构建时发生,而__init__()调用在构建实例时发生。您需要让装饰器将函数转换为描述符,并让该描述符从实例中获取名称。

于 2011-05-28T20:58:10.817 回答
1

只要您仅在方法上使用装饰器,它们就会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'));该name变量是如此通用,但是当您在任意类方法上使用时,您很可能会得到意想不到的结果。

于 2011-05-28T21:20:22.000 回答
1

用作@print_timing类装饰器:

@print_timing
class name(object):
    ...

无需更改;您的包装对象现在应该是一个函数,但它应该是一个类,但我从您的问题(以及它是一个可调用类的事实)推断它并不重要(如果确实如此,您可以将装饰器修改为使返回的包装对象“更漂亮”)。

于 2011-05-28T21:49:12.907 回答