Python Decorator, a function wrapper that allows author to modify behaviour before, and/or after your function/method to be called; In general, there are 2 styles to create decorator, one is using class, and another is to use function. Most of the time people prefer the later one, as it is shorter. But to illustrate how it works, and convey the basic understanding; Class style is more verbose. So lets start with that.

Class style decorator

To get started, here is how basic decoration pattern looks like:

Explanation:

Class definition is there to create a python’s callable object, by leverage on python’s special function __call__, (read this StackOverflow link for more information).

So if you take a look at the Execution Result you will notice that “Creating Decorator” is printed even before, hello() is actually called. That’s because @decorator is being call right on the function declaration. Therefore the wrapping happens there.

Anatomy of “@”

Take a look at this anatomy first.

Intuitively, @ means call d (whatever it is, class or function) with an argument of function f (declared under me). And then call it as f. So this can be translated as …

or

Now since d is actually Python’s class it invokes __init__ on its invocation then it returns the class’s instance which can be invoked again with special __call__ method.

Function style decorator

So if you take a look at big picture, the decorator goal is just “create a wrapped function”, by create a nested callable objects. Function itself is another simplest form of callable object as well. With class, your first callable relies on __init__ then __call__. But with function you just declare and return it. So here is how you can do the previous example in Functions style.

Decorator with arguments

Now in practice, you might want to pass in the arguments to your decorators to customize its function. Here is a very verbose Class Style decorator.

This decorator is actually rely on the same exact anatomy as described earlier. Only one slight different, to illustrate that, let’s revisit our anatomy.

As mentioned d is a Callable object, this time this callable is being created by Class __init__ method (with arguments), which returns a callable instance, now our special __call__ method is invoked for sake of wrapping instead; For that our __call__ method returns the wrapped_f instead of just call we create another function that can be called again.

Of cause you can do this in function style as well. So in the last bit of code. Here is an extremely generic pattern of argument decorator.