0

The goal is to wrap a function or method and carry data around with the wrapper that's unique to the wrapped function.

As an example - let's say I have object myThing with method foo. I want to wrap myThing.foo with myWrapper, and (as an example) I want to be able to count the number of times myThing.foo is actually called.

So far, the only method I've found to be effective is to just add an attribute to the object -- but this feels a little bit clumsy.

class myThing(object):
    def foo(self):
        return "Foo called."

def myWrap(some_func):
    def _inner(self):
        #a wild kludge appears!
        try:
            self.count += 1
        except AttributeError:
            self.count = 0
        return some_func(self)
    return _inner

Stick = myThing()
myThing.foo = myWrap(myThing.foo)
for i in range(0, 10):
    Stick.foo() ##outputs "Foo called." 10 times

Stick.count # the value of Stick.count

So, this achieves the goal, and in fact if there are multiple instances of myThing then each one 'tracks' its own self.count value, which is part of my intended goal. However, I am not certain that adding an attribute to each instance of myThing is the best way to achieve this. If, for example, I were to write a wrapper for a function that wasn't part of an object or class, adding attributes to an object that isn't there won't do anything.

Maybe there is a hole in my understanding of what's actually happening when a method or function is wrapped. I do know that one can maintain some kind of static data within a closure, as with the following example:

def limit(max_value):
    def compare(x):
        return x > max_value
    return compare

isOverLimit = limit(30)
isOverLimit(45) #returns True
isOverLimit(12) #returns False

alsoOver = limit(20)
alsoOver(25) # returns True
isOverLimit(25) # returns False

The second example proving that it's not simply modifying the original instance of limit, and that isOverLimit continues to act as it did before the second alsoOver is created. So I get the sense that there's a way for the wrapper to carry an incremental variable around with it, and that I'm just missing something obvious.

1 Answers1

1

Seems like this is a dupe of Counting python method calls within another method

The short answer is to use a decorator on the method/function you want to count, and have the decorator store the counter as a function attribute. See the answers in the question I linked.

Community
  • 1
  • 1
dano
  • 91,354
  • 19
  • 222
  • 219