Consider the following code fragment.
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()
This returns:
__call__ took 0.000 s ~ 0 min and 0.0 sec
bar
The object bar behaves like a function called bar, but exposes the internal implementation detail of __call__ when used with the decorator print_timing. Is there a way to change the name object (perhaps by passing a suitable argument to the __init__ function) so it returns instead
bar took 0.000 s ~ 0 min and 0.0 sec
? I want a solution that will let the print_timing decorator continue to work with ordinary functions. Running
print foo() gives
foo took 0.000 s ~ 0 min and 0.0 sec
foo
As long as you use the decorator only on methods, they’ll be passed
selfas the first argument:Updated: The wrapper now uses
func.__name__by default, but if you use this on anameclass (as in your original question), it’ll use thenameattribute of the instance instead.I’ve used an
isinstancetest to determine that anameattribute will be present, but you could use duck-typing instead (if hasattr(args[0], 'name')); thenamevariable is so generic however that you most likely will get unexpected results when used on arbitrary class methods.