Mastering Decorators in Python for Cleaner Code
Join our newsletter
Harsh Shah

Harsh Shah

Nov 25,2024

Mastering Decorators in Python for Cleaner Code

Table of contents

  • Prerequisites
  • Functions as variable
  • Using nested functions
  • Basics of decorators
  • Creating a decorator
  • Calling decorators
  • A better way to call decorators
  • Decorators with parameters
  • Exercise

Python Decorators

Python decorators turn out to be an effective tool, if you properly use them. But do we even know how to use them. If not, then you've come to the right place. So without further ado, let's get started.

Prerequisites

To follow along you, you need to know the concept of functions as a variable. If you think you know it, feel free to skip to next heading. If not, I got you covered.

Functions as variable

Consider the following code:

def func1(temp):
    print("Inside func1", temp)
    
def usingFunc(myFunc, value):
    myFunc(value)
    
usingFunc(func1, "This really works!")

# Output => "Inside func1, This really works!"
Now if this confuses you, here is the explanation

As we all heard, that anything in a program gradually boils down to memory locations and the name given to access that location is called variable. So, if it is the truth that means a function is also just a variable unless you call it. Hence, we can pass functions as variables. Now here in the code, we see that we pass the func1 in the function usingFunc . Hope this helps.

Using nested functions

Now if the function is a variable, it also follows it rules, right? You would say "Obviously". And yes you are correct 👏. So now we can also return functions without calling and define a function inside a function. And since the function is a variable, it also has a scope, same as that of a variable.

Here is a quick exercise for you
def outerFunc(key):
    def innerFunc(value):
        print(key, value)
    return innerFunc

inner = outerFunc("Secret Key")
inner("Value")

Find the answer to this. And if you do, leave a comment below and give yourself a good pat.

Basics of decorators

Now here comes the core of the article.

Now the decorator is basically a way to increase the functionality of a function, by wrapping it in another function but in a syntactic manner. Pretty exciting, right?

Creating a decorator

Let's first see how to create a decorator.

def prettify(func):
    def inner():
        print("Decorator called...")
        func()
    return inner

In the code segment above, we have a function inner inside the prettify function. Also the prettify function recieves an argument, i.e., func which is the function to which we want to add additional functionality, or in simpler terms, we want to decorate the func. The prettify function also returns another function reference inner that adds the extra functionality and then calls our functiion func.

Calling decorators

As defined in the previous segment, we can now use the prettify function as decorator. Here is the code to do that

def func():
  print("In a function")

decorated_func = prettify(func)
decorated_func() 

# Output:
# Decorator called...
# In a function 

In the above code, we see that I created a function named func1 and passed it to prettify function as an argument. Now, the prettify function returns a function reference, that has the extra functionality along with the core functionality of func1 . Now we call the function that prettify returned. After calling, the output of the program is given in the code.

A better way to call decorators

Now the essentials of the decorators are over, but why not a bonus? The above code is fine and it works. But is it not cumbersome? If you think it is, welcome to the club. Even the python developers thought so, hence they came up with @ <>{obj.text} symbol. Here's how it works.

@prettify
def func():
  print("Another func...") 

Now this is the same thing as above, the only difference is the writing style. In the above function, we called prettify and passed the function func. Here the python interpreter understands that the prettify function is a decorator because of the @ symbol, and hence, passes the function func by itself. Now we can simply call the function func and it works like a charm! 🌟

Decorators with parameters

The above examples were simple, not with any parameters, but let's say I want to prettify this function

def add(x, y):
  print(x+y)

To do so, we need to modify our prettify function to accomodate so.

def prettify(func):
    def inner(a, b):
        print("Decorator called...")
        func(a, b)
    return inner

If you pay attention, you can see that I added two arguments to the inner function to accomodate the things we need to pass to the add function.

Exercise

  • Predict the output of the following code:
def prettify(func):
    def inner(a, b):
        print("Decorator called...")
        func(a, b)
    return inner

@prettify
def add(x, y):
    print(x+y)

add(19, 21)

Subscribe to our newsletter

Close
Harsh Shah

Harsh Shah

I write articles on web dev and more specifically on react and next js.

Leave a feedback

Related Posts

Categories