Master Python Programming From Scratch

Clear, interactive, and structured coding lessons designed for absolute beginners.

Decorators in Python

Learn how Python decorators can add extra functionality to an existing function without changing its original code.

What is a Decorator?

A decorator is a function that adds extra behavior to another function.

Decorators allow us to modify or extend the behavior of a function without changing the original function code.

Simple Definition: A decorator is a function that takes another function and adds extra functionality to it.

Decorator Flow

Original Function

The function contains the main logic.

↓
Decorator

Adds extra functionality around the function.

↓
Modified Behavior

The function runs with the additional behavior.

Basic Syntax

def decorator(function):

    def wrapper():

        function()

    return wrapper


@decorator
def welcome():

    print("Welcome to Python")

The @decorator syntax tells Python to apply the decorator to the function.

Simple Decorator Example

def message_decorator(function):

    def wrapper():

        print("Before function")

        function()

        print("After function")

    return wrapper


@message_decorator
def welcome():

    print("Welcome to Python")


welcome()

Output:

Before function
Welcome to Python
After function

The decorator adds statements before and after the original function.

Applying Decorator Without @

A decorator can also be applied directly by assigning the decorated function.

def decorator(function):

    def wrapper():

        print("Before")

        function()

        print("After")

    return wrapper


def welcome():

    print("Welcome")


welcome = decorator(welcome)

welcome()

Output:

Before
Welcome
After

Decorator with Function Parameters

A decorator can also work with functions that receive parameters.

def decorator(function):

    def wrapper(name):

        print("Welcome message")

        function(name)

    return wrapper


@decorator
def greet(name):

    print("Hello", name)


greet("Rahul")

Output:

Welcome message
Hello Rahul

Decorator with Multiple Arguments

We can use *args and **kwargs when the decorated function may receive different numbers of arguments.

def decorator(function):

    def wrapper(*args, **kwargs):

        print("Function started")

        result = function(*args, **kwargs)

        print("Function completed")

        return result

    return wrapper


@decorator
def add(a, b):

    return a + b


print(add(10, 20))

Output:

Function started
Function completed
30

Decorator with Return Value

A decorator can return the result produced by the original function.

def decorator(function):

    def wrapper(a, b):

        result = function(a, b)

        return result

    return wrapper


@decorator
def multiply(a, b):

    return a * b


print(multiply(5, 4))

Output:

20

Practical Example: Login Check

Decorators can be used to perform a check before allowing a function to execute.

def login_required(function):

    def wrapper(user):

        if user == "admin":

            return function(user)

        else:

            print("Access denied")

    return wrapper


@login_required
def dashboard(user):

    print("Welcome to dashboard")


dashboard("admin")

Output:

Welcome to dashboard

Multiple Decorators

More than one decorator can be applied to the same function.

def first(function):

    def wrapper():

        print("First decorator")

        function()

    return wrapper


def second(function):

    def wrapper():

        print("Second decorator")

        function()

    return wrapper


@first
@second
def welcome():

    print("Welcome")


welcome()

Output:

First decorator
Second decorator
Welcome

Preserving Function Information

The functools.wraps function can be used when we want to preserve information about the original function.

from functools import wraps

def decorator(function):

    @wraps(function)
    def wrapper():

        return function()

    return wrapper


@decorator
def welcome():

    print("Welcome to Python")


welcome()

This is commonly used when creating reusable decorators.

Common Uses of Decorators

Authentication

Check whether a user is allowed to access a function.

Logging

Record when functions are executed.

Validation

Validate conditions before executing a function.

Advantages of Decorators

Code Reusability

The same decorator can be used with multiple functions.

Less Repetition

Common logic does not need to be repeated in every function.

Clean Code

Additional behavior can be separated from the main function logic.

Best Practices

Keep Decorators Small

Keep the decorator focused on one responsibility.

Use Meaningful Names

Give decorators clear and descriptive names.

Use wraps

Use functools.wraps when the original function information should be preserved.

Common Mistakes

  • Forgetting to return the wrapper function.
  • Forgetting to return the result of the original function.
  • Not handling function arguments correctly.
  • Creating very complicated decorators for simple tasks.
  • Forgetting to use functools.wraps when function metadata needs to be preserved.

Practice Programs

  1. Create a decorator that prints a message before a function runs.
  2. Create a decorator that prints a message after a function runs.
  3. Create a decorator that accepts function arguments.
  4. Create a decorator for checking user login.
  5. Create a decorator that calculates the execution time of a function.

Summary

A decorator is a function that adds extra functionality to another function without changing its original code. Decorators are useful for logging, authentication, validation and reusable common functionality. They can work with arguments, return values and multiple decorators can be applied to the same function.