DEV Community

Lini Abraham
Lini Abraham

Posted on

Python Decorators

Decorators

WHAT?

A decorator in Python is a special kind of function that adds extra functionality to another function, without changing the original function’s code.

WHY?

To add some functionality before or after a function is executed as a wrapper around the original function
To create a standardised pattern for reusability across various functions
To follow DRY ( Do not repeat yourself ) in the code

HOW?


Example 1: A simple function with no decorators

def greet():
    print("Hello!")

Enter fullscreen mode Exit fullscreen mode

A sample decorator function

def log_function_call(func):
    def wrapper():
        print(f"Starting function {func.__name__}")
        func()
        print(f"Finished function {func.__name__}")
    return wrapper
Enter fullscreen mode Exit fullscreen mode

Use the decorator by adding "@" before the decorator function and add it above the function definition you want to wrap it with

@log_function_call
def greet():
    print("Hello!")
Enter fullscreen mode Exit fullscreen mode

Call the greet function

greet()
Enter fullscreen mode Exit fullscreen mode

greet function call execution result

Starting function greet
Hello!
Finished function greet
Enter fullscreen mode Exit fullscreen mode

Example 2: Decorators with Arguments *args and **kwargs

Decorator function with args and kwargs

def log_function_call(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with:")
        print(f"Positional arguments: {args}")
        print(f"Keyword arguments: {kwargs}")
        result = func(*args, **kwargs)
        print("Done.")
        return result
    return wrapper
Enter fullscreen mode Exit fullscreen mode

Original function definition with the decorator function added

@log_function_call
def create_order(customer_name, *items, delivery=False, **extras):
    print(f"Creating order for: {customer_name}")
    print(f"Items: {items}")
    print(f"Delivery requested? {'Yes' if delivery else 'No'}")
    print(f"Extra options: {extras}")
    return "Order Created"
Enter fullscreen mode Exit fullscreen mode

Call the original function

create_order(
    "Alexander",
    "Laptop", "Mouse", "Charger",
    delivery=True,
    gift_wrap=True,
    note="Deliver after 1 pm"
)
Enter fullscreen mode Exit fullscreen mode

Function call execution result

Calling create_order with:
Positional arguments: ('Alexander', 'Laptop', 'Mouse', 'Charger')
Keyword arguments: {'delivery': True, 'gift_wrap': True, 'note': 'Deliver after 1 pm'}

Creating order for: Alexander
Items: ('Laptop', 'Mouse', 'Charger')
Delivery requested? Yes
Extra options: {'gift_wrap': True, 'note': 'Deliver after 1 pm'}
Done.
Enter fullscreen mode Exit fullscreen mode

Example 3: Pass a function as an argument to a decorator

Scenario: Role-Based Access Control (RBAC)

You’re building an app with different users: admin, manager, and guest.

You want to restrict access to some functions based on role.

So, let’s:
1. Write a check_permission function
2. Pass it into a decorator
3. Let the decorator use that to decide whether to run the original function

Define permission check functions

def admin_only(user):
    return user.get("role") == "admin"

def manager_or_admin(user):
    return user.get("role") in ("admin", "manager")
Enter fullscreen mode Exit fullscreen mode

Create the decorator that accepts a permission function

def authorize(permission_function):
    def decorator(original_function):
        def wrapper(user, *args, **kwargs):
            if permission_function(user):
                print(f"Access granted to {user['name']}")
                return original_function(user, *args, **kwargs)
            else:
                print(f"Access denied for {user['name']} ({user['role']})")
        return wrapper
    return decorator
Enter fullscreen mode Exit fullscreen mode

Decorate your protected functions

@authorize(admin_only)
def delete_user(user, target_username):
    print(f"{user['name']} deleted user: {target_username}")

@authorize(manager_or_admin)
def view_reports(user):
    print(f"{user['name']} is viewing reports.")
Enter fullscreen mode Exit fullscreen mode

Calling the function

admin_user = {"name": "Alice", "role": "admin"}
manager_user = {"name": "Bob", "role": "manager"}
guest_user = {"name": "Eve", "role": "guest"}

delete_user(admin_user, "John")
delete_user(guest_user, "John")

view_reports(manager_user)
view_reports(guest_user)
Enter fullscreen mode Exit fullscreen mode

Function call result

Access granted to Alice
Alice deleted user: John
Access denied for Eve (guest)
Access granted to Bob
Bob is viewing reports.
Access denied for Eve (guest)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)