Decorators in Python

Decorators in Python

A decorator is a function that modifies the behavior of another function without permanently modifying it. Decorators are a powerful tool that use closure functions.

Basic Concept

A decorator:

  1. Takes a function as input
  2. Returns a modified function (or a new function)
  3. Uses the @decorator_name syntax

Simple Example

python

def simple_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

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

# Using the decorated function
say_hello()

Output:

text

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

Equivalent Without @ Syntax

python

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

# Manual decoration
decorated_hello = simple_decorator(say_hello)
decorated_hello()

Decorator for Functions with Arguments

python

def smart_divide(func):
    def wrapper(a, b):
        print(f"Dividing {a} by {b}")
        if b == 0:
            print("Cannot divide by zero!")
            return
        return func(a, b)
    return wrapper

@smart_divide
def divide(a, b):
    return a / b

print(divide(10, 2))  # Output: Dividing 10 by 2 → 5.0
print(divide(10, 0))  # Output: Dividing 10 by 0 → Cannot divide by zero!

Decorator with Any Number of Arguments

python

def logger(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned: {result}")
        return result
    return wrapper

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

@logger
def multiply(x, y, z=1):
    return x * y * z

add(3, 5)
multiply(2, 3, z=4)

Output:

text

Calling add with args: (3, 5), kwargs: {}
add returned: 8
Calling multiply with args: (2, 3), kwargs: {'z': 4}
multiply returned: 24

Practical Example: Timing Function Execution

python

import time

def timer(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

@timer
def slow_function():
    time.sleep(2)
    return "Done!"

slow_function()  # Output: slow_function executed in 2.0002 seconds

Chaining Decorators

python

def bold(func):
    def wrapper():
        return "<b>" + func() + "</b>"
    return wrapper

def italic(func):
    def wrapper():
        return "<i>" + func() + "</i>"
    return wrapper

@bold
@italic
def hello():
    return "Hello World"

print(hello())  # Output: <b><i>Hello World</i></b>

Decorator with Arguments

python

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(n):
                print(f"Call {i+1}:")
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Output:

text

Call 1:
Hello, Alice!
Call 2:
Hello, Alice!
Call 3:
Hello, Alice!

Why Use Decorators?

  • Code Reuse: Avoid repetitive code
  • Separation of Concerns: Keep business logic separate from cross-cutting concerns
  • Readability: Makes code more readable and maintainable
  • Extensibility: Easy to add/remove functionality

Decorators are widely used in web frameworks (like Flask, Django), testing, logging, and many other areas of Python programming!

Similar Posts

  • Linear vs. Scalar,Homogeneous vs. Heterogeneous 

    Linear vs. Scalar Data Types in Python In programming, data types can be categorized based on how they store and organize data. Two important classifications are scalar (atomic) types and linear (compound) types. 1. Scalar (Atomic) Data Types 2. Linear (Compound/Sequential) Data Types Key Differences Between Scalar and Linear Data Types Feature Scalar (Atomic) Linear (Compound) Stores Single…

  • Generalization vs. Specialization

    Object-Oriented Programming: Generalization vs. Specialization Introduction Inheritance in OOP serves two primary purposes: Let’s explore these concepts with clear examples. 1. Specialization (Extending Functionality) Specialization involves creating a new class that inherits all features from a parent class and then adds new, specific features. The core idea is reusability—you build upon what already exists. Key Principle: Child Class =…

  • circle,Rational Number

    1. What is a Rational Number? A rational number is any number that can be expressed as a fraction where both the numerator and the denominator are integers (whole numbers), and the denominator is not zero. The key idea is ratio. The word “rational” comes from the word “ratio.” General Form:a / b Examples: Non-Examples: 2. Formulas for Addition and Subtraction…

  • Keyword-Only Arguments in Python and mixed

    Keyword-Only Arguments in Python Keyword-only arguments are function parameters that must be passed using their keyword names. They cannot be passed as positional arguments. Syntax Use the * symbol in the function definition to indicate that all parameters after it are keyword-only: python def function_name(param1, param2, *, keyword_only1, keyword_only2): # function body Simple Examples Example 1: Basic Keyword-Only Arguments…

  • Classes and Objects in Python

    Classes and Objects in Python What are Classes and Objects? In Python, classes and objects are fundamental concepts of object-oriented programming (OOP). Real-world Analogy Think of a class as a “cookie cutter” and objects as the “cookies” made from it. The cookie cutter defines the shape, and each cookie is an instance of that shape. 1. Using type() function The type() function returns…

Leave a Reply

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