Attaching a decorator to all functions within a class Attaching a decorator to all functions within a class python python

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)