Classes in Python can be extended by inheritance. In Python 3 ability to make a class-decorator was added per PEP request.

Check out that you can make a type of inheritance from decorator to add something to method like in this example

To The Point

How to make your own class decorator? First you need a class definition so let's create one :

class MyFancyClass:
    def __call__(self):
        print("You were calling sir?!")

fancy_object = MyFancyClass()
fancy_object()

Now we can create our class decorator:

def fancy_class_decorator(cls):
    old_init = cls.__init__
    def new_init(self, *args, **kwargs):
        old_init(self, *args, **kwargs)
        print("here goes your additional code to init!")
    cls.__init__ = new_init
    return cls

And using decorator :

@fancy_class_decorator
class MyFancyClass:
    def __call__(self):
        print("You were calling sir?!")

fancy_object = MyFancyClass()
fancy_object()

While I was researching topic I've found that making a class-only fields that are not initialized within constructor can lead to a bad results.

Check out this:

def fancy_class_decorator(cls):
    old_init = cls.__init__
    def new_init(self, *args, **kwargs):
        self.onevar = "fancy_decorator_before"
        self.before = "fancy_decorator_before"

        old_init(self, *args, **kwargs)

        self.onevar = "fancy_decorator_after"
        self.after = "fancy_decorator_after"

    cls.__init__ = new_init
    return cls

@fancy_class_decorator
class MyFancyClass:
    onevar = "class"
    before = "class"
    after = "class"

    def __call__(self):
        print("onevar", self.onevar)
        print("before", self.before)
        print("after", self.after)

fancy_object = MyFancyClass()
fancy_object()

And then This:

def fancy_class_decorator(cls):
    old_init = cls.__init__
    def new_init(self, *args, **kwargs):
        self.onevar = "fancy_decorator_before"
        self.before = "fancy_decorator_before"

        old_init(self, *args, **kwargs)

        self.onevar = "fancy_decorator_after"
        self.after = "fancy_decorator_after"

    cls.__init__ = new_init
    return cls

@fancy_class_decorator
class MyFancyClass:
    def __init__(self):
        self.onevar = "class"
        self.before = "class"
        self.after = "class"

    def __call__(self):
        print("onevar", self.onevar)
        print("before", self.before)
        print("after", self.after)

fancy_object = MyFancyClass()
fancy_object()

First example presents situation where you create a class-based fields which are not initialized within constructor of class.

Because we are making a decorator-inheritance over constructor, it automatically changes fields data.

Snippets

Replace old_method with method you want to make decorator-inheritance on.

def class_decorator(cls):
    old_method = cls.method
    def new_method(self, *args, **kwargs):
        old_method(self, *args, **kwargs)

    cls.old_method = new_method
    return cls

Acknowledgements

Auto-promotion:

Found related to post:

Not related, but also time-worth:

Thanks!

That's it :) Comment, share or don't :)

If you have any suggestions what I should blog about in the next articles - please give me a hint :)

See you in the next episode! Cheers!



Comments

comments powered by Disqus