Decorator inside Python class

Let’s suppose we need a decorator that we gonna use inside one specific class only. Something like this:

Where to define this decorator?

Function inside class

The immediate urge is to put atomic_rating_change into the class itself:

That would actually work, but there is major flaw in this approach: atomic_rating_change becomes an instance method of theUser class. That doesn’t make any sense. More than this, it doesn’t even work as a method: if you call it, the decorated parameter will be used as self.

Note, that within the class body atomic_rating_change is still a plain function. It becomes a method only after the class is actually created, and at this time the decorator is already successfully applied.

Here is a small example that may help you understand this concept:

You can see indeed that func is a function within the class body, but it’s a method outside of the class. Moreover, A.func and A().func values differ too, thanks to Python descriptor magic (if you are unfamiliar with descriptors in Python, you should check the link). In Python 3 A.func is just a plain function though.

What can we do to make this work properly? Here are some ideas.

Make it static (don’t)

The simple thing you do every time you want to store just a plain function in a class is just to make it a static method.

You may think that it resolves all the problems completely, but sadly it doesn’t. staticmethod is another descriptor, and descriptors behave differently inside and outside of a class (yeah, again).

So, once you apply this decorator to some method you get TypeError: 'staticmethod' object is not callable, because you see a raw descriptor inside the class.

Declare outside

The most simple solution you are probably already thinking of is to declare function outside of the class.

The only downside is the function is not anyhow bound to the class anymore.

Declare in another class

To fix this we can declare a helper class that contains all the decorators for User:

UserDecorators isn’t bound to the original class either (save the name), but since it’s not a function anymore, we can put it in User!

Declare in inner class

You also can make Decorators private (by renaming it to _Decorators) if you don’t like other classes to use your decorator.

This solution is pretty solid and recommended, but there is one appealing method I’m aware of.

Make class, not method

Thanks to Python __call__ magic method, you can declare any decorator as a class, not as a function. Recall, that our initial problem is functions behaving differently inside and outside of a class body, but that doesn’t apply at all to classes inside a class body (look at the Decorators in the previous examples: it works just fine). So converting the decorator from the first example to a class would work perfectly.

Fun fact: both working solutions involve changing the inner function to the inner class (due to the specific behaviour of function attributes, duh).

Note that the described problem is not of a conceptual nature, it’s just a way to fight the fact that a function can’t be a simple class attribute in Python.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store