How to create a (transparent) decorator with status information?

Discussion in 'Python' started by Timo Schmiade, Apr 18, 2011.

  1. 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

    Thinking object-orientedly, my first idea was to use an object as a
    decorator:

    class CallCounter:
    def __init__(self, decorated):
    self.__function = decorated
    self.__numCalls = 0

    def __call__(self, *args, **kwargs):
    self.__numCalls += 1
    return self.__function(*args, **kwargs)

    # To support decorating member functions
    def __get__(self, obj, objType):
    return functools.partial(self.__call__, obj)

    This approach however has three problems (let "decorated" be a function
    decorated by either call_counts or CallCounter):

    * The object is not transparent to the user like call_counts is. E.g.
    help(decorated) will return CallCounter's help and decorated.func_name
    will result in an error although decorated is a function.
    * 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).
    * I can't get the information from the decorator, so unless CallCounter
    emits the information on its own somehow (e.g. by using print), the
    decorator is completely pointless.

    So, my question is: What would the "pythonic" way to implement a
    decorator with status information be? Or am I missing the point of
    decorators and am thinking in completely wrong directions?

    Thanks in advance!

    Kind regards,

    Timo
     
    Timo Schmiade, Apr 18, 2011
    #1
    1. Advertising

  2. Hey Wayne,

    On Mon, Apr 18, 2011 at 04:04:15PM -0700, Wayne Witzel III wrote:
    > Going with the object approach, you could use Borg to give yourself the state between instances you mentioned. And since you are using an object, you'll have access to the data without needing to return it from the decorator.
    >
    > class StatefulDecorators(object):
    > _state = {}
    > def __new__(cls, *p, **k):
    > self = object.__new__(cls, *p, **k)
    > self.__dict__ = cls._state
    > return self
    >
    > def count_calls(self, function):
    > @functools.wraps(function)
    > def wrapper(*args, **kwargs):
    > try:
    > self.calls += 1
    > except AttributeError:
    > self.calls = 1
    > return function(*args, **kwargs)
    > return wrapper


    Brilliant! I didn't realize you could use member functions as
    decorators, too! That way, you can easily create closures to self,
    solving all the problems I was seeing.

    Just one question remains now: What is a "Borg" in this context?

    Thank you.

    Timo
     
    Timo Schmiade, Apr 19, 2011
    #2
    1. Advertising

  3. Timo Schmiade

    Ian Kelly Guest

    Ian Kelly, Apr 19, 2011
    #3
  4. Timo Schmiade, Apr 19, 2011
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    7
    Views:
    14,220
    tonnie
    Jul 21, 2006
  2. glomde
    Replies:
    5
    Views:
    526
    glomde
    Mar 29, 2007
  3. WT
    Replies:
    5
    Views:
    491
    Steven Cheng[MSFT]
    May 21, 2007
Loading...

Share This Page