How to create a (transparent) decorator with status information?
Ian Kelly
ian.g.kelly at gmail.com
Mon Apr 18 15:07:58 EDT 2011
On Mon, Apr 18, 2011 at 6:47 AM, Timo Schmiade <the_isz at gmx.de> wrote:
> Hi all,
>
> I'm currently occupying myself with python's decorators and have some
> questions as to their usage. Specifically, I'd like to know how to
> design a decorator that maintains a status. Most decorator examples I
> encountered use a function as a decorator, naturally being stateless.
>
> Consider the following:
>
> def call_counts(function):
> @functools.wraps(function):
> def wrapper(*args, **kwargs):
> # No status, can't count #calls.
> return function(*args, **kwargs)
> return wrapper
In the simple case, just store the state on the wrapper function itself:
def call_counts(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
wrapper.num_calls += 1
return function(*args, **kwargs)
wrapper.num_calls = 0
return wrapper
@call_counts
def f():
pass
f()
f()
print(f.num_calls)
> * The maintained status is not shared among multiple instances of the
> decorator. This is unproblematic in this case, but might be a problem
> in others (e.g. logging to a file).
If you want the state to be shared, you should probably store it in an
object and use an instance method as the decorator:
class CallCounter(object):
def __init__(self):
self.num_calls = 0
def call_counts(self, function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
self.num_calls += 1
return function(*args, **kwargs)
return wrapper
call_counter = CallCounter()
@call_counter.call_counts
def f1_with_shared_counts():
pass
@call_counter.call_counts
def f2_with_shared_counts():
pass
Cheers,
Ian
More information about the Python-list
mailing list