Decorators in Python: A Complete Guide

Naveen PnNaveen Pn
3 min read

Introduction to Decorators

Decorators in Python are a powerful tool that allows modifying or extending the behavior of functions without altering their actual implementation. They make code more readable, reusable, and maintainable by allowing modifications to functions in a clean and efficient way.

Why Use Decorators?

  • Code Reusability: Avoid repeating code for similar functionalities.

  • Separation of Concerns: Keeps function logic independent of additional behavior.

  • Enhanced Readability: Makes functions cleaner by abstracting modifications.

  • Useful for Logging, Authentication, Timing Functions, and More.

Basic Syntax of a Decorator

A decorator is a function that takes another function as input and extends its behavior.

Step 1: Creating a Basic Decorator

def my_decorator(func):
    def wrapper():
        print("Something before the function runs.")
        func()
        print("Something after the function runs.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello, World!")

say_hello()

Output:

Something before the function runs.
Hello, World!
Something after the function runs.

How It Works

  • my_decorator(func) receives the function say_hello().

  • wrapper() adds additional behavior before and after calling func().

  • @my_decorator applies the decorator to say_hello(), modifying its behavior.

Decorators with Arguments

If the decorated function takes arguments, use *args and **kwargs inside the wrapper.

def smart_decorator(func):
    def wrapper(*args, **kwargs):
        print("Executing decorated function...")
        result = func(*args, **kwargs)
        print("Finished execution.")
        return result
    return wrapper

@smart_decorator
def add(a, b):
    return a + b

print(add(5, 3))

Output:

Executing decorated function...
Finished execution.
8

Built-in Decorators in Python

Python provides several built-in decorators, commonly used for modifying methods in classes.

1. @staticmethod

Defines a function inside a class that doesnโ€™t require access to instance attributes.

class MathOperations:
    @staticmethod
    def add(a, b):
        return a + b

print(MathOperations.add(5, 3))  # Output: 8

2. @classmethod

Allows methods to receive the class itself (cls) instead of instance (self).

class MyClass:
    class_var = "Hello"

    @classmethod
    def show_class_var(cls):
        return cls.class_var

print(MyClass.show_class_var())  # Output: Hello

3. @property

Used to define read-only properties in a class.

class Person:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

p = Person("Mahesh")
print(p.name)  # Output: Mahesh

Using Multiple Decorators

You can stack multiple decorators on a single function:

def decorator1(func):
    def wrapper():
        print("Decorator 1 before function")
        func()
        print("Decorator 1 after function")
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2 before function")
        func()
        print("Decorator 2 after function")
    return wrapper

@decorator1
@decorator2
def hello():
    print("Hello, World!")

hello()

Output:

Decorator 1 before function
Decorator 2 before function
Hello, World!
Decorator 2 after function
Decorator 1 after function

Real-World Applications of Decorators

1. Logging Function Execution

import time

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Executing {func.__name__} at {time.strftime('%X')}")
        return func(*args, **kwargs)
    return wrapper

@log_decorator
def greet(name):
    print(f"Hello, {name}!")

greet("Mahesh")

2. Checking User Authentication

def requires_authentication(func):
    def wrapper(user, *args, **kwargs):
        if user == "admin":
            return func(*args, **kwargs)
        else:
            print("Access Denied")
    return wrapper

@requires_authentication
def secure_action():
    print("Performing secure action...")

secure_action("user")   # Output: Access Denied
secure_action("admin")  # Output: Performing secure action...

3. Timing Function Execution

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timer_decorator
def slow_function():
    time.sleep(2)
    print("Finished processing.")

slow_function()

Output:

Finished processing.
slow_function took 2.0001 seconds
1
Subscribe to my newsletter

Read articles from Naveen Pn directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Naveen Pn
Naveen Pn

I am a Tech Enthusiast having 13+ years of experience in ๐ˆ๐“ as a ๐‚๐จ๐ง๐ฌ๐ฎ๐ฅ๐ญ๐š๐ง๐ญ, ๐‚๐จ๐ซ๐ฉ๐จ๐ซ๐š๐ญ๐ž ๐“๐ซ๐š๐ข๐ง๐ž๐ซ, ๐Œ๐ž๐ง๐ญ๐จ๐ซ, with 12+ years in training and mentoring in ๐’๐จ๐Ÿ๐ญ๐ฐ๐š๐ซ๐ž ๐„๐ง๐ ๐ข๐ง๐ž๐ž๐ซ๐ข๐ง๐ , ๐ƒ๐š๐ญ๐š ๐„๐ง๐ ๐ข๐ง๐ž๐ž๐ซ๐ข๐ง๐ , ๐“๐ž๐ฌ๐ญ ๐€๐ฎ๐ญ๐จ๐ฆ๐š๐ญ๐ข๐จ๐ง ๐š๐ง๐ ๐ƒ๐š๐ญ๐š ๐’๐œ๐ข๐ž๐ง๐œ๐ž. I have ๐’•๐’“๐’‚๐’Š๐’๐’†๐’… ๐’Ž๐’๐’“๐’† ๐’•๐’‰๐’‚๐’ 10,000+ ๐‘ฐ๐‘ป ๐‘ท๐’“๐’๐’‡๐’†๐’”๐’”๐’Š๐’๐’๐’‚๐’๐’” and ๐’„๐’๐’๐’…๐’–๐’„๐’•๐’†๐’… ๐’Ž๐’๐’“๐’† ๐’•๐’‰๐’‚๐’ 500+ ๐’•๐’“๐’‚๐’Š๐’๐’Š๐’๐’ˆ ๐’”๐’†๐’”๐’”๐’Š๐’๐’๐’” in the areas of ๐’๐จ๐Ÿ๐ญ๐ฐ๐š๐ซ๐ž ๐ƒ๐ž๐ฏ๐ž๐ฅ๐จ๐ฉ๐ฆ๐ž๐ง๐ญ, ๐ƒ๐š๐ญ๐š ๐„๐ง๐ ๐ข๐ง๐ž๐ž๐ซ๐ข๐ง๐ , ๐‚๐ฅ๐จ๐ฎ๐, ๐ƒ๐š๐ญ๐š ๐€๐ง๐š๐ฅ๐ฒ๐ฌ๐ข๐ฌ, ๐ƒ๐š๐ญ๐š ๐•๐ข๐ฌ๐ฎ๐š๐ฅ๐ข๐ณ๐š๐ญ๐ข๐จ๐ง๐ฌ, ๐€๐ซ๐ญ๐ข๐Ÿ๐ข๐œ๐ข๐š๐ฅ ๐ˆ๐ง๐ญ๐ž๐ฅ๐ฅ๐ข๐ ๐ž๐ง๐œ๐ž ๐š๐ง๐ ๐Œ๐š๐œ๐ก๐ข๐ง๐ž ๐‹๐ž๐š๐ซ๐ง๐ข๐ง๐ . I am interested in ๐ฐ๐ซ๐ข๐ญ๐ข๐ง๐  ๐›๐ฅ๐จ๐ ๐ฌ, ๐ฌ๐ก๐š๐ซ๐ข๐ง๐  ๐ญ๐ž๐œ๐ก๐ง๐ข๐œ๐š๐ฅ ๐ค๐ง๐จ๐ฐ๐ฅ๐ž๐๐ ๐ž, ๐ฌ๐จ๐ฅ๐ฏ๐ข๐ง๐  ๐ญ๐ž๐œ๐ก๐ง๐ข๐œ๐š๐ฅ ๐ข๐ฌ๐ฌ๐ฎ๐ž๐ฌ, ๐ซ๐ž๐š๐๐ข๐ง๐  ๐š๐ง๐ ๐ฅ๐ž๐š๐ซ๐ง๐ข๐ง๐  new subjects.