Decorate a class

Let’s start with a base class:

class Foo(object):

    def __init__(self):
        self.iamfoo = True
>>> f = Foo()
>>> f.iamfoo
True

Decorator without arguments

If we need to add an attribute with a fixed value such a boolean or an integer that will never change, it is done this way:

def addRefund(cls):

    class Refund(cls):

        def __init__(self, *args, **kargs):
            super().__init__(*args, **kargs)
            self.refund = True

    return Refund

Use it like this:

@addRefund
class Foo(object):

    def __init__(self):
        self.iamfoo = True
>>> f = Foo()
>>> f.iamfoo
True
>>> f.refund
True

Decorator with arguments

If we need to add attributes that don’t have a fixed value, we can do it like this:

def addRange(start, end):

    def decorator(cls):

        class Range(cls):

            def __init__(self, *args, **kargs):
                super().__init__(*args, **kargs)
                self.hasrange = True
                self.start = start
                self.end = end

        return Range

    return decorator

Use it like this:

@addRange(1,5)
class Foo(object):

    def __init__(self):
        self.iamfoo = True
>>> f = Foo()
>>> f.iamfoo
True
>>> f.hasrange
True
>>> f.start
1
>>> f.end
5

Decorators with default arguments

Of course, you can also use default arguments within a decorator:

def addRange(start=1, end=10):

    def decorator(cls):

        class Range(cls):

            def __init__(self, *args, **kargs):
                super().__init__(*args, **kargs)
                self.hasrange = True
                self.start = start
                self.end = end

        return Range

    return decorator

Use it like this:

@addRange()
class Foo(object):

    def __init__(self):
        self.iamfoo = True
>>> f = Foo()
>>> f.iamfoo
True
>>> f.hasrange
True
>>> f.start
1
>>> f.end
10