Skip to content

Decorators & Generators πŸš€

Mentor's Note: Decorators and Generators are what make Python feel "Magic." They allow you to add features to code without changing it, and process millions of lines of data without crashing your RAM! πŸ’‘


🌟 The Scenario: The Gift Wrapper 🎁

Imagine you have a shop that sells plain boxes.

  • The Decorator (The Wrapper): A customer wants a box, but they want it wrapped in Shiny Paper ✨ and a Ribbon πŸŽ€. You don't build a new box; you just "Wrap" the existing one. πŸ“¦
  • The Generator (The Candy Machine): A customer wants 1,000 candies. Instead of handing them a giant heavy bag (A List), you give them a Candy Machine 🍬. They turn the handle, and get one candy at a time whenever they are ready.
  • The Result: You save space in your shop and make the customer happy! βœ…

πŸ“– Concept Explanation

1. Python Decorators

A decorator is a function that takes another function and extends its behavior without explicitly modifying it. - Syntax: @decorator_name placed above a function.

2. Python Generators

Generators are special functions that return an Iterator object. They use the yield keyword instead of return. - Logic: "I'm not finished, just pausing here. Call me again for the next item!" ⏸️


🎨 Visual Logic: The Generator Flow

graph TD
    A[Start Generator] --> B[Run until 'yield']
    B --> C[Pause and Return Value 🍬]
    C --> D{Need next item?}
    D -- Yes --> B
    D -- No --> E[Stop / Close Machine 🏁]

πŸ’» Implementation: The Advanced Lab

# πŸ›’ Scenario: Adding a 'Log' to every action
# πŸš€ Action: Creating a logger decorator

def log_action(func):
    def wrapper():
        print("LOG: Action is starting... πŸ•’")
        func()
        print("LOG: Action finished. βœ…")
    return wrapper

@log_action
def say_hello():
    print("Hello, VishnuDigital!")

say_hello()
# πŸ›’ Scenario: Infinite Counter (Memory Safe)
# πŸš€ Action: Using yield to save RAM

def count_up_to(max_val):
    count = 1
    while count <= max_val:
        yield count # 🍬 Hands out one number and pauses
        count += 1

# Using the generator
counter = count_up_to(1000000)
print(next(counter)) # 1
print(next(counter)) # 2

πŸ“Š Sample Dry Run (Generators)

Function: yield 1; yield 2;

Turn Status Action Output
1 Started Run until 1st yield 1
2 Paused Resume and run until 2nd yield 2
3 Finished No more yields found StopIteration 🏁

πŸ“‰ Technical Analysis

  • Memory Efficiency: A list of 1 million numbers takes ~40MB of RAM. A generator for 1 million numbers takes ~100 bytes. 🀯
  • Lazy Evaluation: Generators only calculate the next value when you actually ask for it.

🎯 Practice Lab πŸ§ͺ

Task: The Timer Decorator

Task: Create a decorator @timer that prints how many seconds a function takes to run. Hint: Use import time and calculate end_time - start_time. πŸ’‘


πŸ’‘ Interview Tip πŸ‘”

"Interviewers love asking: 'What is the difference between yield and return?' Answer: return destroys the function's local state and exits. yield pauses the function, saves its state, and can be resumed later!"


πŸ’‘ Pro Tip: "Writing clean code is what you do when you care about the people who will read itβ€”including yourself in six months!" - Anonymous


← Back: Algorithms | Next: Regex & Multiprocessing β†’