Ricardo Aráoz wrote: > Hi, I'm trying to count method calls. Tried this but... >>>>> class MyList(list): >> ... def __init__(self): >> ... self.calls = 0
should call list.__init__(self) here. >> ... def __getattr__(self, name): >> ... self.calls += 1 >> ... return list.__getattribute__(self, name) >> >>>>> a = MyList() >>>>> a >> [] >>>>> a.append(1) >>>>> a >> [1] >>>>> a.calls >> 88 >>>>> a.append(3) >>>>> a.calls >> 88 >>>>> a.sort() >>>>> a >> [1, 3] >>>>> a.calls >> 176 > > It's doing some strange things with self.calls. What version of Python are you using? When I try this program it prints 0 0 0 Note that __getattr__() is only called when normal attribute access *fails*, so I would not expect this to work. > I've also tried : > >>>>> class MyList(list): >> ... def __init__(self): >> ... self.calls = 0 >> ... def __getattribute__(self, name): # Here's the change >> ... self.calls += 1 >> ... return list.__getattribute__(self, name) >> >>>>> a = MyList() >>>>> a >> [] >>>>> a.append(1) > File "<input>", line 5, in __getattribute__ > File "<input>", line 5, in __getattribute__ > .... snipped ..... > File "<input>", line 5, in __getattribute__ > File "<input>", line 5, in __getattribute__ > RuntimeError: maximum recursion depth exceeded > > Any idea what's going on in both tries? And how can I intercept method > calls without defining all of list's methods. The problem here is that __getattribute__() is called for *all* attribute access including getting the value of self.calls to increment it. So __getattribute__() calls itself without end which is the recipe for a stack overflow. If you change getattribute() to this it is closer to what you want: def __getattribute__(self, name): self.calls = list.__getattribute__(self, 'calls') + 1 return list.__getattribute__(self, name) For me this prints 2 4 6 with your sequence of operations. More problems - this counts *any* attribute access, not just callables. You could change it to get the attribute and only count it if callable(value) is true. But it also counts calls to implementation methods which is probably not what you want - if list.sort() calls three other methods, do you want a count of 4 for a call to sort()? And it counts failed attribute access; that is easy to fix by incrementing calls after the call to list.__getattribute__(). A different approach is to use delegation rather than inheritance to access the list functions. Write __getattr__() to delegate to a list attribute: class MyList(object): def __init__(self): self._list = list() self.calls = 0 def __getattr__(self, name): value = getattr(self._list, name) if callable(value): self.calls += 1 return value I think this does what you want. Notice that it doesn't have anything special to do with lists, either, except instantiating a list. It can be turned into a general-purpose counting wrapper by passing the instance to be counted to the constructor: class CallCounter(object): def __init__(self, delegate): self._delegate = delegate self.calls = 0 def __getattr__(self, name): value = getattr(self._delegate, name) if callable(value): self.calls += 1 return value a = CallCounter(list()) etc. Kent _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor