Decorators
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