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: 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:
returndestroys the function's local state and exits.yieldpauses 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