¿Cómo decorar todas las funciones de una clase sin tener que escribirlas una y otra vez para cada método?

Digamos que mi clase tiene muchos métodos, y quiero aplicar mi decorador en cada uno de ellos, más adelante, cuando agregué nuevos métodos, quiero que se aplique el mismo decorador, pero no quiero escribir @mydecorator sobre la statement del método all ¿el tiempo?

Si miro __call__ es ese el camino correcto?

IMPORTANTE: el siguiente ejemplo parece estar resolviendo un problema diferente del que se formuló en la pregunta original.

EDITAR: Me gustaría mostrarlo de esta manera, que es una solución similar a mi problema para cualquier persona que encuentre esta pregunta más adelante, utilizando una mezcla como se menciona en los comentarios.

 class WrapinMixin(object): def __call__(self, hey, you, *args): print 'entering', hey, you, repr(args) try: ret = getattr(self, hey)(you, *args) return ret except: ret = str(e) raise finally: print 'leaving', hey, repr(ret) 

Luego puedes en otro

 class Wrapmymethodsaround(WrapinMixin): def __call__: return super(Wrapmymethodsaround, self).__call__(hey, you, *args) 

Decora la clase con una función que recorre los atributos de la clase y decora los callables. Esto puede ser incorrecto si tiene variables de clase que pueden llamarse, y también decorará las clases anidadas (créditos para Sven Marnach por señalarlo), pero en general es una solución bastante simple y limpia. Ejemplo de implementación (tenga en cuenta que esto no excluirá métodos especiales ( __init__ etc.), que pueden o no ser deseados):

 def for_all_methods(decorator): def decorate(cls): for attr in cls.__dict__: # there's propably a better way to do this if callable(getattr(cls, attr)): setattr(cls, attr, decorator(getattr(cls, attr))) return cls return decorate 

Use así:

 @for_all_methods(mydecorator) class C(object): def m1(self): pass def m2(self, x): pass ... 

En Python 3.0 y 3.1, el nombre no existe. Existió desde siempre en Python 2.x y está de vuelta en Python 3.2 como envoltorio para isinstance(x, collections.Callable) , por lo que puede usar eso (o definir su propio reemplazo con este) en esas versiones.

Si bien no me gusta usar los enfoques mágicos cuando lo haría un enfoque explícito, probablemente pueda usar una metaclase para esto.

 def myDecorator(fn): fn.foo = 'bar' return fn class myMetaClass(type): def __new__(cls, name, bases, local): for attr in local: value = local[attr] if callable(value): local[attr] = myDecorator(value) return type.__new__(cls, name, bases, local) class myClass(object): __metaclass__ = myMetaClass def baz(self): print self.baz.foo 

y funciona como si cada una de las myClass en myClass hubiera sido decorada con myDecorator

 >>> quux = myClass() >>> quux.baz() bar 

No para revivir las cosas de los muertos, pero realmente me gustó la respuesta de Delnan, pero me pareció que faltaba.

 def for_all_methods(exclude, decorator): def decorate(cls): for attr in cls.__dict__: if callable(getattr(cls, attr)) and attr not in exclude: setattr(cls, attr, decorator(getattr(cls, attr))) return cls return decorate 

EDITAR: corregir sangría

Así que puedes especificar los métodos // atributos // cosas que no quieres decorar

Ninguna de las respuestas anteriores funcionó para mí, ya que también quería decorar los métodos heredados, lo que no se logró mediante el uso de __dict__ , y no quería complicar demasiado las cosas con las metaclases. Por último, estoy de acuerdo con tener una solución para Python 2, ya que simplemente necesito agregar un código de perfil para medir el tiempo utilizado por todas las funciones de una clase.

 import inspect def for_all_methods(decorator): def decorate(cls): for name, fn in inspect.getmembers(cls, inspect.ismethod): setattr(cls, name, decorator(fn)) return cls return decorate 

Fuente (solución ligeramente diferente): https://stackoverflow.com/a/3467879/1243926 Allí también puede ver cómo cambiarlo para Python 3.

Como lo sugieren los comentarios a otras respuestas, considere usar inspect.getmembers(cls, inspect.isroutine) lugar. Si ha encontrado una solución adecuada que funcione tanto para Python 2 como Python 3 y decore los métodos heredados, y aún se puede hacer en 7 líneas, edite.

Podrías generar una metaclase. Esto no decorará los métodos heredados.

 def decorating_meta(decorator): class DecoratingMetaclass(type): def __new__(self, class_name, bases, namespace): for key, value in list(namespace.items()): if callable(value): namespace[key] = decorator(value) return type.__new__(self, class_name, bases, namespace) return DecoratingMetaclass 

Esto generará una metaclase decorando todos los métodos con la función especificada. Puedes usarlo en Python 2 o 3 haciendo algo como esto

 def doubling_decorator(f): def decorated(*a, **kw): return f(*a, **kw) * 2 return decorated class Foo(dict): __metaclass__ = decorating_meta(doubling_decorator) def lookup(self, key): return self[key] d = Foo() d["bar"] = 5 print(d.lookup("bar")) # prints 10