Advanced Patterns: Decorators & Generators

Python provides unique features that allow you to write highly efficient and extensible code. Decorators and Generatorsare two of the most powerful.

1. Decorators (@)

Decorators allow you to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it.

def my_decorator(func):
    def wrapper():
        print("--- Start ---")
        func()
        print("--- End ---")
    return wrapper

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

say_hello()

2. Generators (yield)

Generators are functions that allow you to declare a function that behaves like an iterator. They use the yield keyword to return data lazily.

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

counter = count_up_to(5)
for n in counter:
    print(n)

Why use Generators?

Generators are memory-efficient. Instead of creating a huge list in memory, they generate one item at a time only when needed. This is critical for processing massive data files.

Note: Most modern Python frameworks (like Flask and FastAPI) use decorators heavily for routing and dependency injection.