2011-06-15 26 views
5

Supongamos que tengo alguna clase simplemétodos de decorar por ejemplo en Python

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

me gustaría decorar el método doSomething, por ejemplo, para contar el número de llamadas

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) 

Ahora bien, esta cuenta el número de llamadas al método decorado; sin embargo, me gustaría tener un contador por instancia, de modo que después de

foo1=TestClass() 
foo1.doSomething() 
foo2=TestClass() 

foo1.doSomething.count es 1 y foo2.doSomething.count es 0. Por lo que entiendo, esto no es posible usando decoradores. ¿Hay alguna forma de lograr tal comportamiento?

Respuesta

10

Utilizar el hecho de que self (es decir, el objeto que se invoca el método a) se pasa como un parámetro para el método:

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 

En el código anterior, interceptar el objeto como obj parámetro del decorado versión del método. El uso del decorador es bastante sencillo:

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

¿No sería el primer elemento de *args el objeto en el que se invoca el método? ¿No puedes simplemente almacenar el conteo allí?

+0

Sí, creo que eso sería posible. Pero se siente como un diseño subóptimo para mí, ya que el decorador se basaría en las propiedades de la clase en la que se usa para hacerlo más difícil de usar. – Christoph

Cuestiones relacionadas