Search code examples
pythondecorator

How to decorate a class?


How do I create a decorator that applies to classes?

Specifically, I want to use a decorator addID to add a member __id to a class, and change the constructor __init__ to take an id argument for that member.

def getId(self): return self.__id

classdecorator addID(cls):
    def __init__(self, id, *args, **kws):
        self.__id = id
        self.getId = getId
        cls.__init__(self, *args, **kws)

@addID
class Foo:
    def __init__(self, value1):
        self.value1 = value1

The above should be equivalent to:

class Foo:
    def __init__(self, id, value1):
        self.__id = id
        self.value1 = value1

    def getId(self): return self.__id

Solution

  • I would second the notion that you may wish to consider a subclass instead of the approach you've outlined. However, not knowing your specific scenario, YMMV :-)

    What you're thinking of is a metaclass. The __new__ function in a metaclass is passed the full proposed definition of the class, which it can then rewrite before the class is created. You can, at that time, sub out the constructor for a new one.

    Example:

    def substitute_init(self, id, *args, **kwargs):
        pass
    
    class FooMeta(type):
    
        def __new__(cls, name, bases, attrs):
            attrs['__init__'] = substitute_init
            return super(FooMeta, cls).__new__(cls, name, bases, attrs)
    
    class Foo(object):
    
        __metaclass__ = FooMeta
    
        def __init__(self, value1):
            pass
    

    Replacing the constructor is perhaps a bit dramatic, but the language does provide support for this kind of deep introspection and dynamic modification.