Function Decorators in Python?

Python developers can extend and modify the behavior of a callable functions, methods or classes without permanently modifying the callable itself by using decorators. In short we can say they are callable objects which are used to modify functions or classes.

Function decorators are functions which accepts function references as arguments and adds a wrapper around them and returns the function with the wrapper as a new function.

Let’s understand function decorator bye an example:


def func(arg):
   return "value"

Above code is same as:


def func(arg):
   return "value"
func = decorator(func)

So from above, we can see a decorator is simply another function which takes a function as an argument and returns one.

Decorators basically “decoratre” or “wrap” another function and let you execute code before and after the wrapped function runs as explained in below example:

def our_decorator(func):
   def function_wrapper(x):
      print("Before calling " + func.__name__)
      print("After calling " + func.__name__)
   return function_wrapper

def foo(x):
   print("Hi, foo has been called with " + str(x))

print("We call foo before decoration:")

print("We now decorate foo with f:")
foo = our_decorator(foo)

print("We call foo after decoration:")


We call foo before decoration:
Hi, foo has been called with Hi
We now decorate foo with f:
We call foo after decoration:
Before calling foo
Hi, foo has been called with 90
After calling foo

If you think above is little bit complex, let write the simplest possible decorator:

def null_decorator(func):
   return func

Above null_decorator is a callable(function), it takes another callable as its input and it returns the same input callable without modifying it.

Let’s extend our above simplest decorator by decorating (or wrap) another function.

def null_decorator(func):
   return func
def greet():
   return "Hello, Python!"

greet = null_decorator(greet)
>>> greet()
'Hello, Python!'

Above we have defined a greet function and then immediately decorated it by running it through the null_decorator function.

Much simpler way to writing above python decorative program (instead of explicitly calling null_decorator on greet and then reassigning the greet variable) is to use python @syntax for decorating a function in one step:

def greet():
   return "Hello, Python!"
>>> greet()
'Hello, Python!'