Site icon Full-Stack

Decorators and Generators in Python: A Powerful Duo Explained

Python is renowned for its robust features and ease of use. The capacity to build code that is clearer, more effective, and reusable makes decorators and generators stand out among them. Knowing these two ideas will improve your coding skills, whether you’re a novice moving into intermediate-level Python or getting ready for an interview.

What are Decorators in Python?

In Python, a decorator is a design pattern that lets you change a function’s or class method’s behavior without altering the source code.

Consider it similar to wrapping a present. You improve its appearance without changing the gift within.

Key Use Cases:

Basic Decorator Syntax

def my_decorator(func):
    def wrapper():
        print("Before the function runs.")
        func()
        print("After the function runs.")
    return wrapper

@my_decorator
def greet():
    print("Hello, World!")

greet()

Output:

Before the function runs.
Hello, World!
After the function runs.

Here, @my_decorator is syntactic sugar for greet = my_decorator(greet)

Real-Life Example: Logging Decorator

def log_function(func):
    def wrapper(*args, **kwargs):
        print(f"Function '{func.__name__}' called with {args} and {kwargs}")
        return func(*args, **kwargs)
    return wrapper

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

print(add(5, 3))

What are Generators in Python?

A generator is a function that, as opposed to returning all values at once as lists do, returns an iterator and gives values one at a time.

Generators save memory and are ideal for handling infinite sequences or big datasets.

Generator Syntax with yield

def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

for number in count_up_to(5):
    print(number)

Output:

1
2
3
4
5

The function preserves its state and continues where it left off each time it is called.

Use Case: Reading Large Files Line by Line

def read_large_file(file_path):
    with open(file_path) as file:
        for line in file:
            yield line.strip()

for line in read_large_file("huge_file.txt"):
    print(line)

Combining Decorators and Generators

Even generator functions can be decorated to provide timing or logging.

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        for value in func(*args, **kwargs):
            yield value
        end = time.time()
        print(f"Execution took {end - start:.4f} seconds")
    return wrapper

@timer
def generate_numbers():
    for i in range(5):
        time.sleep(0.5)
        yield i

for num in generate_numbers():
    print(num)

You can also read for:- What is the Python Standard Library?

Benefits of Using Decorators and Generators

FeatureDecoratorsGenerators
Code ReuseWrap functionality around othersResume execution with yield
ReadabilityCleaner, DRY (Don’t Repeat Yourself)Avoid large memory usage
FlexibilityCan stack multiple decoratorsInfinite or lazy sequences
PerformanceAdd logging, caching, etc. easilyEfficient for loops and streams

Summary

You also like this:-

Introduction to Serverless Databases: Firebase, AWS DynamoDB, & More
Top 10 Backend Frameworks in 2025: Which One Should You Choose?

What is Python Programming? Your Complete Guide to Understanding Python

Exit mobile version