Python - Decorators in Python — Detailed Explanation

A decorator in Python is a design pattern that allows you to modify or extend the behavior of a function or method without changing its actual code. It is essentially a function that takes another function as input and returns a new function with added functionality.


1. Basic Idea

In Python, functions are first-class objects, meaning:

  • You can pass them as arguments

  • You can return them from other functions

  • You can assign them to variables

A decorator uses this property.


2. Simple Example Without Decorator Syntax

def greet():
    print("Hello")

def my_decorator(func):
    def wrapper():
        print("Before function execution")
        func()
        print("After function execution")
    return wrapper

greet = my_decorator(greet)
greet()

Output:

Before function execution
Hello
After function execution

Here:

  • my_decorator takes greet as input

  • It wraps it inside another function (wrapper)

  • Adds extra behavior before and after execution


3. Using Decorator Syntax (@)

Python provides a cleaner way using @ syntax.

def my_decorator(func):
    def wrapper():
        print("Before function execution")
        func()
        print("After function execution")
    return wrapper

@my_decorator
def greet():
    print("Hello")

greet()

This is equivalent to:

greet = my_decorator(greet)

4. Decorators with Arguments

If the original function takes parameters, the wrapper must accept them.

def my_decorator(func):
    def wrapper(name):
        print("Before execution")
        func(name)
        print("After execution")
    return wrapper

@my_decorator
def greet(name):
    print(f"Hello {name}")

greet("Alice")

5. Using *args and **kwargs

To handle any number of arguments:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before execution")
        result = func(*args, **kwargs)
        print("After execution")
        return result
    return wrapper

This makes the decorator reusable for any function.


6. Returning Values from Decorated Functions

def my_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result * 2
    return wrapper

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

print(add(2, 3))  # Output: 10

7. Real-World Use Cases

Decorators are widely used in real applications:

a) Logging

def log(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

b) Authentication (Web apps)

  • Check if a user is logged in before running a function

c) Timing Functions

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        func(*args, **kwargs)
        end = time.time()
        print("Time:", end - start)
    return wrapper

d) Caching (memoization)


8. Preserving Function Metadata

When you use decorators, the original function name and docstring get replaced.

To fix this, use functools.wraps:

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

9. Decorators with Arguments (Advanced)

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello")

say_hello()

10. Key Points to Remember

  • A decorator is a function that wraps another function

  • It adds functionality without modifying original code

  • Uses closures (functions inside functions)

  • Common in frameworks like Flask, Django

  • Improves code reusability and cleanliness


Summary

Decorators provide a powerful way to:

  • Add functionality dynamically

  • Keep code clean and modular

  • Avoid repetition

They are especially important in advanced Python programming and are heavily used in real-world applications such as web development, logging systems, and performance optimization.