Attaching a decorator to all functions within a class
The cleanest way to do this, or to do other modifications to a class definition, is to define a metaclass.
Alternatively, just apply your decorator at the end of the class definition using inspect
:
import inspectclass Something: def foo(self): passfor name, fn in inspect.getmembers(Something, inspect.isfunction): setattr(Something, name, decorator(fn))
In practice of course you'll want to apply your decorator more selectively. As soon as you want to decorate all but one method you'll discover that it is easier and more flexible just to use the decorator syntax in the traditional way.
Everytime you think of changing class definition, you can either use the class decorator or metaclass. e.g. using metaclass
import typesclass DecoMeta(type): def __new__(cls, name, bases, attrs): for attr_name, attr_value in attrs.iteritems(): if isinstance(attr_value, types.FunctionType): attrs[attr_name] = cls.deco(attr_value) return super(DecoMeta, cls).__new__(cls, name, bases, attrs) @classmethod def deco(cls, func): def wrapper(*args, **kwargs): print "before",func.func_name result = func(*args, **kwargs) print "after",func.func_name return result return wrapperclass MyKlass(object): __metaclass__ = DecoMeta def func1(self): passMyKlass().func1()
Output:
before func1after func1
Note: it will not decorate staticmethod and classmethod
Following code works for python2.x and 3.x
import inspectdef decorator_for_func(orig_func): def decorator(*args, **kwargs): print("Decorating wrapper called for method %s" % orig_func.__name__) result = orig_func(*args, **kwargs) return result return decoratordef decorator_for_class(cls): for name, method in inspect.getmembers(cls): if (not inspect.ismethod(method) and not inspect.isfunction(method)) or inspect.isbuiltin(method): continue print("Decorating function %s" % name) setattr(cls, name, decorator_for_func(method)) return cls@decorator_for_classclass decorated_class: def method1(self, arg, **kwargs): print("Method 1 called with arg %s" % arg) def method2(self, arg): print("Method 2 called with arg %s" % arg)d=decorated_class()d.method1(1, a=10)d.method2(2)