Deploy Django, Flask, and FastAPI in seconds

Connect the git repository and deploy your app on the fully managed Kubernetes.

Share

3 min read

Master Python Decorators: A Beginner’s Guide with Examples

Introduction

Python decorators are a powerful feature that allows you to modify the behavior of functions or classes without altering their code. They are widely used for logging, enforcing access control, instrumentation, caching, and more. Understanding decorators is essential for writing clean, reusable, and maintainable Python code.

What Are Python Decorators?

A decorator in Python is a function that takes another function as input and extends its behavior without explicitly modifying it. It allows for code reusability and cleaner implementations.

Example:

def decorator_function(original_function):
    def wrapper_function():
        print(f"Wrapper executed before {original_function.__name__}")
        return original_function()
    return wrapper_function

@decorator_function
def say_hello():
    print("Hello!")

say_hello()

Output:

Wrapper executed before say_hello
Hello!

The @ Syntax for Decorators

Python provides a convenient syntax for applying decorators using the @ symbol. This is equivalent to manually passing a function into the decorator.

Example:

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

@my_decorator
def greet():
    print("Greetings!")

greet()

This syntax eliminates the need to wrap functions manually.

How to Create Your Own Decorators

Creating custom decorators is simple. Follow these steps:

  1. Define a function that accepts another function.
  2. Define a nested wrapper function.
  3. Modify or extend the behavior of the input function.
  4. Return the wrapper function.

Example: Logging Decorator

import time

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

@timing_decorator
def compute():
    time.sleep(1)
    print("Computation finished!")

compute()

Use Cases for Decorators

Decorators are widely used in real-world applications. Some common use cases include:

  • Logging: Automatically log function calls and execution time.
  • Access Control: Restrict access to certain users.
  • Caching: Store results of expensive computations.
  • Validation: Validate input parameters.

Example: Authentication Decorator

def requires_authentication(func):
    def wrapper(user, *args, **kwargs):
        if not user.get("is_authenticated", False):
            print("Access denied. Please log in.")
            return
        return func(user, *args, **kwargs)
    return wrapper

@requires_authentication
def view_dashboard(user):
    print("Welcome to your dashboard!")

user = {"is_authenticated": False}
view_dashboard(user)

user["is_authenticated"] = True
view_dashboard(user)

Common Mistakes and Best Practices

Mistakes:

  1. Forgetting to use functools.wraps: Losing function metadata.
  2. Not handling function arguments properly: Use *args and **kwargs.
  3. Overusing decorators: Can make debugging harder.

Best Practices:

  • Use functools.wraps(func) to preserve function metadata.
  • Keep decorators simple and reusable.
  • Document your decorators properly.

Example Fix:

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Before the function call")
        result = func(*args, **kwargs)
        print("After the function call")
        return result
    return wrapper

Conclusion

Python decorators are an essential tool for writing clean, efficient, and reusable code. By mastering decorators, you can enhance the readability and maintainability of your Python applications.

Try using a decorator in your next project!

Further Reading

Previous Post
How To Create Singleton Methods In Python
Next Post
4 Strange Things About “and” & “or” in Python

Master Python Decorators: A Beginner’s Guide with Examples

Introduction

Python decorators are a powerful feature that allows you to modify the behavior of functions or classes without altering their code. They are widely used for logging, enforcing access control, instrumentation, caching, and more. Understanding decorators is essential for writing clean, reusable, and maintainable Python code.

What Are Python Decorators?

A decorator in Python is a function that takes another function as input and extends its behavior without explicitly modifying it. It allows for code reusability and cleaner implementations.

Example:

def decorator_function(original_function):
    def wrapper_function():
        print(f"Wrapper executed before {original_function.__name__}")
        return original_function()
    return wrapper_function

@decorator_function
def say_hello():
    print("Hello!")

say_hello()

Output:

Wrapper executed before say_hello
Hello!

The @ Syntax for Decorators

Python provides a convenient syntax for applying decorators using the @ symbol. This is equivalent to manually passing a function into the decorator.

Example:

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

@my_decorator
def greet():
    print("Greetings!")

greet()

This syntax eliminates the need to wrap functions manually.

How to Create Your Own Decorators

Creating custom decorators is simple. Follow these steps:

  1. Define a function that accepts another function.
  2. Define a nested wrapper function.
  3. Modify or extend the behavior of the input function.
  4. Return the wrapper function.

Example: Logging Decorator

import time

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

@timing_decorator
def compute():
    time.sleep(1)
    print("Computation finished!")

compute()

Use Cases for Decorators

Decorators are widely used in real-world applications. Some common use cases include:

  • Logging: Automatically log function calls and execution time.
  • Access Control: Restrict access to certain users.
  • Caching: Store results of expensive computations.
  • Validation: Validate input parameters.

Example: Authentication Decorator

def requires_authentication(func):
    def wrapper(user, *args, **kwargs):
        if not user.get("is_authenticated", False):
            print("Access denied. Please log in.")
            return
        return func(user, *args, **kwargs)
    return wrapper

@requires_authentication
def view_dashboard(user):
    print("Welcome to your dashboard!")

user = {"is_authenticated": False}
view_dashboard(user)

user["is_authenticated"] = True
view_dashboard(user)

Common Mistakes and Best Practices

Mistakes:

  1. Forgetting to use functools.wraps: Losing function metadata.
  2. Not handling function arguments properly: Use *args and **kwargs.
  3. Overusing decorators: Can make debugging harder.

Best Practices:

  • Use functools.wraps(func) to preserve function metadata.
  • Keep decorators simple and reusable.
  • Document your decorators properly.

Example Fix:

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Before the function call")
        result = func(*args, **kwargs)
        print("After the function call")
        return result
    return wrapper

Conclusion

Python decorators are an essential tool for writing clean, efficient, and reusable code. By mastering decorators, you can enhance the readability and maintainability of your Python applications.

Try using a decorator in your next project!

Further Reading

Previous Post
How To Create Singleton Methods In Python
Next Post
4 Strange Things About “and” & “or” in Python