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

AltStyle によって変換されたページ (->オリジナル) /