2011-06-15 4 views
5

Supposons que j'ai une classe simpleméthodes Décore par exemple en Python

class TestClass: 
    def doSomething(self): 
     print 'Did something' 

Je voudrais décorer la méthode doSomething, par exemple pour compter le nombre d'appels

class SimpleDecorator(object): 
    def __init__(self,func): 
     self.func=func 
     self.count=0 
    def __get__(self,obj,objtype=None): 
     return MethodType(self,obj,objtype) 
    def __call__(self,*args,**kwargs): 
     self.count+=1 
     return self.func(*args,**kwargs) 

Maintenant, ce compte le nombre d'appels à la méthode décorée, mais je voudrais avoir compteur par instance, de sorte que après

foo1.doSomething.count est 1 et foo2.doSomething.count est 0. D'après ce que je comprends, ce n'est pas possible en utilisant des décorateurs. Y a-t-il un moyen d'atteindre un tel comportement?

Répondre

10

Utiliser le fait que self (à savoir l'objet de la méthode est invoquée sur) est passé en paramètre à la méthode:

import functools 

def counted(method): 
    @functools.wraps(method) 
    def wrapped(obj, *args, **kwargs): 
     if hasattr(obj, 'count'): 
      obj.count += 1 
     else: 
      obj.count = 1 
     return method(obj, *args, **kwargs) 
    return wrapped 

Dans le code ci-dessus, nous intercepter l'objet comme obj paramètre de la décoration version de la méthode. L'utilisation du décorateur est assez simple:

class Foo(object): 
    @counted 
    def do_something(self): pass 
1

Le premier élément de *args ne serait-il pas l'objet sur lequel la méthode est appelée? Tu ne peux pas juste stocker le compte là?

+0

Oui, je suppose que ce serait possible. Mais cela me semble être une conception sous-optimale, car le décorateur s'appuierait sur les propriétés de la classe utilisée pour le rendre plus difficile à utiliser. – Christoph

Questions connexes