What Are Python Decorators with Arguments? See Examples

Decorators in Python are functions that modify the behavior of other functions. Sometimes, you may want to pass parameters to a decorator to customize its behavior. This is done by adding an extra layer of function nesting.

Decorators with arguments are widely used in logging, authentication, validation, and dynamic functionality.


Why Decorators with Arguments Are Important

  • Make decorators more flexible and reusable
  • Enable dynamic behavior customization
  • Useful in web frameworks and APIs
  • Allow parameterized logging or validation

Basic Syntax

def decorator_with_args(arg):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"Decorator argument: {arg}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

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

greet("Python")

Output:

Decorator argument: Hello
Hi Python

Example 1: Logging with Arguments

def log(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"[{level}] Function {func.__name__} called with {args} {kwargs}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@log("INFO")
def add(a, b):
    return a + b

print(add(5, 3))

Output:

[INFO] Function add called with (5, 3) {}
8

Example 2: Authorization Decorator

def authorize(role):
    def decorator(func):
        def wrapper(user_role, *args, **kwargs):
            if user_role != role:
                print("Access Denied")
                return
            return func(*args, **kwargs)
        return wrapper
    return decorator

@authorize("admin")
def delete_user(user_id):
    print(f"User {user_id} deleted")

delete_user("admin", 101)  # Access granted
delete_user("guest", 102)  # Access Denied

Example 3: Real-World Scenario – Timing Decorator with Arguments

import time

def timer(unit="seconds"):
    def decorator(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            elapsed = end - start
            if unit == "milliseconds":
                elapsed *= 1000
            print(f"Execution time: {elapsed:.2f} {unit}")
            return result
        return wrapper
    return decorator

@timer("milliseconds")
def compute():
    sum([i**2 for i in range(100000)])

compute()

Best Practices

✔ Use decorators with arguments for flexible, reusable code
✔ Keep wrapper functions simple
✔ Preserve function metadata with functools.wraps
✔ Avoid over-nesting decorators for readability


Conclusion

Python decorators with arguments allow dynamic and reusable modifications of function behavior. They are widely used in real-world applications such as logging, authentication, and performance measurement.


References

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *