Python Advance Course

Decorators in Python (Advanced)

Decorators in Python (Advanced)

A decorator is a function that modifies another function without changing its actual code.

Decorators are built using: - Functions - Closures - Higher-order functions


Basic Idea of Decorators

A decorator: - Takes a function as input - Adds extra behavior - Returns a new function


1. Function Decorators

Basic decorator example:

def decorator(func):
    def wrapper():
        print("Before function runs")
        func()
        print("After function runs")
    return wrapper


def say_hello():
    print("Hello")

decorated = decorator(say_hello)
decorated()

Output:

Before function runs
Hello
After function runs

Using @ syntax (Pythonic way)

def decorator(func):
    def wrapper():
        print("Before")
        func()
        print("After")
    return wrapper


@decorator
def greet():
    print("Good Morning")

greet()

Real World Example

Scenario Decorator Use
Login check authentication
Logging request logs
Timing performance check

Graph (Flow)

greet()
  |
  v
wrapper()
  |
  +--> Before logic
  +--> Original function
  +--> After logic

Common Mistake

@decorator()
def func():
    print("Hi")

Error: - Missing function reference

Correct:

@decorator

Homework 1

Create a decorator that prints: - "Start" - "End"

Solution:

def decorator(func):
    def wrapper():
        print("Start")
        func()
        print("End")
    return wrapper


@decorator
def hello():
    print("Hello World")

hello()

2. Decorator Chaining

Multiple decorators can be applied to one function.

Example:

def deco1(func):
    def wrapper():
        print("Decorator 1")
        func()
    return wrapper


def deco2(func):
    def wrapper():
        print("Decorator 2")
        func()
    return wrapper


@deco1
@deco2
def show():
    print("Original Function")

show()

Output:

Decorator 1
Decorator 2
Original Function

Execution Flow

@deco1
   ↓
@deco2
   ↓
function()

Real World Example

Layer Use
Authentication login check
Authorization permission check
Logging request logs

Homework 2

Create two decorators: - One prints "A" - Another prints "B"

Apply both to a function.


3. Decorators with Arguments

Sometimes decorators need parameters.

Example:

def repeat(n):
    def decorator(func):
        def wrapper():
            for i in range(n):
                func()
        return wrapper
    return decorator


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

hello()

Output:

Hello
Hello
Hello

Real World Example

Use Case Example
Retry system retry 3 times
Logging level debug/info
Rate limiting 5 requests

Graph

repeat(n)
   ↓
decorator(func)
   ↓
wrapper()
   ↓
loop execution

Common Mistake

@repeat
def func():
    print("Hi")

Problem: - Missing argument

Correct:

@repeat(3)

Homework 3

Create a decorator that repeats function 5 times.


4. functools.wraps

When using decorators, function metadata is lost.

Example problem:

def decorator(func):
    def wrapper():
        return func()
    return wrapper


@decorator
def hello():
    "This is hello function"
    print("Hello")

print(hello.__name__)

Output:

wrapper

Fix using wraps

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper():
        return func()
    return wrapper


@decorator
def hello():
    print("Hello")

print(hello.__name__)

Output:

hello

Why wraps is important

Without wraps With wraps
wrapper name shown original name preserved
loses docstring keeps metadata

Homework 4

Apply wraps in a decorator and check function name.


5. Real-World Decorators


Logging Decorator

def log(func):
    def wrapper(*args, **kwargs):
        print("Function is running")
        return func(*args, **kwargs)
    return wrapper


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

print(add(5, 3))

Output:

Function is running
8

Authentication Decorator

def login_required(func):
    def wrapper(user):
        if user == "admin":
            return func(user)
        return "Access Denied"
    return wrapper


@login_required
def dashboard(user):
    return "Welcome Admin"

print(dashboard("admin"))

Timing Decorator

import time

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

Real World Mapping

Decorator Use Case
logging system logs
auth login check
timer performance monitoring
retry API retry logic

Summary Table

Concept Meaning
Decorator modifies function behavior
Chaining multiple decorators
Arguments parameterized decorators
wraps preserves metadata

Decorator Flow Diagram

function
   ↓
decorator(func)
   ↓
wrapper()
   ↓
modified behavior

Homework 5 (Final Challenge)

Create a decorator that: - logs function name - logs arguments - logs result


Solution

def logger(func):
    def wrapper(*args, **kwargs):
        print("Function:", func.__name__)
        print("Args:", args)
        result = func(*args, **kwargs)
        print("Result:", result)
        return result
    return wrapper


@logger
def multiply(a, b):
    return a * b

multiply(4, 5)

Next Advanced Topics

  • Generators
  • Iterators
  • Context Managers
  • Async Programming (async/await)
  • functools (partial, reduce, lru_cache)
  • Metaclasses ```

Filters

No filters available for this view.

Reset All