Introduction 🌟
A generator in Python is a special type of function that returns values **one at a time** using the yield keyword instead of return. Generators are extremely memory-efficient because they produce items **on demand**.
Note
1. What Makes Generators Special? 🧠
- Use yield instead of return.
- Do NOT store all values in memory.
- Execution pauses and resumes on every yield.
- Automatically create an iterator.
2. Basic Generator Function 🧱
basic_generator.py
def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1
for num in count_up_to(5):
print(num)✔️ Values print one at a time, without storing all 5 numbers at once.
3. Generator vs Normal Function ⚔️
| Normal Function | Generator Function |
|---|---|
| Uses return | Uses yield |
| Returns once | Returns multiple values lazily |
| Stores all data | Produces data one-by-one |
| Not memory efficient | Very memory efficient |
4. Using next() to Manually Control Generators 🎮
next_generator.py
gen = count_up_to(3)
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# next(gen) → StopIterationNote
5. Generator Expressions ⚡ (Short Syntax)
Similar to list comprehensions but with **( ) parentheses**.
generator_expression.py
squares = (x * x for x in range(1, 6))
for s in squares:
print(s)Note
6. Infinite Generators ♾️
infinite_generator.py
def infinite_counter():
n = 1
while True:
yield n
n += 1
gen = infinite_counter()
print(next(gen))
print(next(gen))
print(next(gen))Note
7. Generator for Large Data Files 📁
read_file_generator.py
def read_lines(filename):
with open(filename) as file:
for line in file:
yield line.strip()
for line in read_lines("data.txt"):
print(line)✔️ Efficient for reading large files line by line.
8. Chaining Generators 🔗
chain_generators.py
def numbers():
for i in range(1, 6):
yield i
def squares():
for n in numbers():
yield n * n
print(list(squares()))✔️ Output: [1, 4, 9, 16, 25]
9. Sending Data to Generators (send()) 📤
send_generator.py
def greeter():
name = yield "Enter your name:"
yield f"Hello {name}"
gen = greeter()
print(next(gen)) # Start generator
print(gen.send("Sathish"))Note
10. Using yield from (Delegating Generators) 🔁
yield_from.py
def gen1():
yield from [1, 2, 3]
def gen2():
yield from gen1()
yield 4
print(list(gen2()))✔️ Output: [1, 2, 3, 4]
11. Catching StopIteration 🚨
stop_iteration.py
def simple():
yield 1
yield 2
gen = simple()
try:
while True:
print(next(gen))
except StopIteration:
print("Done")12. Real-World Examples 🌍
Streaming Sensor Data
sensor_stream.py
def sensor():
import random
while True:
yield random.randint(1, 100)
gen = sensor()
print(next(gen)) # simulated sensor readingPagination Generator
pagination.py
def paginate(items, size):
for i in range(0, len(items), size):
yield items[i:i+size]
pages = paginate(list(range(20)), 5)
for p in pages:
print(p)Prime Numbers Generator
prime_generator.py
def is_prime(n):
if n < 2: return False
for i in range(2, n):
if n % i == 0:
return False
return True
def primes(limit):
for x in range(limit):
if is_prime(x):
yield x
print(list(primes(20)))Conclusion 🎉
You now fully understand Generators in Python! Want the next topic? Try Decorators, Modules, Iterators, or OOP (Classes & Objects). Just tell me! 😊
yield — The Heart of GeneratorsIntroduction 🌟
The yield keyword is used in a function to turn it into agenerator. Unlike return, which ends a function completely,yield pauses the function, saves its state, and returns a value. When the function is called again, it resumes exactly where it left off.
Note
yield = pause + return💡
return = stop + return1. Basic Example 🧱
yield_basic.py
def demo():
yield 1
yield 2
yield 3
for x in demo():
print(x)✔️ Each yield produces one value at a time.
2. How yield Works Internally 🧠
- The function starts execution.
- When
yieldis reached → it returns a value and pauses. - Next call resumes from the paused line.
- Ends when no more
yieldstatements are left.
3. Difference Between return and yield ⚔️
| return | yield |
|---|---|
| Ends function completely | Pauses function |
| Returns one value | Returns multiple values lazily |
| Function cannot resume | Function resumes on next call |
| Memory-heavy | Memory efficient |
4. yield in a Loop 🔁
yield_loop.py
def count(n):
for i in range(1, n + 1):
yield i
for x in count(5):
print(x)✔️ Produces numbers from 1 to 5, one at a time.
5. Using next() with yield 🎮
yield_next.py
gen = count(3)
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# next(gen) → StopIterationNote
StopIteration is raised when the generator is exhausted.6. Multiple yield Statements 🧩
yield_multiple.py
def mixed():
yield 10
yield "hello"
yield True
print(list(mixed()))7. yield from — Delegating to Sub-Generators 🔗
yield_from.py
def gen1():
yield from [1, 2, 3]
def gen2():
yield from gen1()
yield 4
print(list(gen2()))✔️ Combines multiple generators cleanly.
8. Using yield for Infinite Sequences ♾️
yield_infinite.py
def infinite_counter():
n = 1
while True:
yield n
n += 1
gen = infinite_counter()
print(next(gen))
print(next(gen))
print(next(gen))Note
9. Returning Final Value with StopIteration 🛑
yield_return.py
def sample():
yield 1
yield 2
return "Done" # This becomes StopIteration value
gen = sample()
try:
while True:
print(next(gen))
except StopIteration as e:
print("Final:", e.value)✔️ return inside a generator signals a final value.
10. Sending Data Back into Generator (send()) 📤
yield_send.py
def greeter():
name = yield "Enter your name:"
yield f"Hello {name}"
gen = greeter()
print(next(gen)) # Start → asks for name
print(gen.send("Sathish"))11. Real-World Examples 🌍
✔ Reading Large Files Efficiently
yield_file.py
def read_lines(filename):
with open(filename) as file:
for line in file:
yield line.strip()
for line in read_lines("data.txt"):
print(line)✔ Pagination System
yield_pagination.py
def paginate(data, size):
for i in range(0, len(data), size):
yield data[i:i+size]
for page in paginate(range(20), 5):
print(list(page))✔ Sensor Data Stream
yield_sensor.py
import random
def sensor():
while True:
yield random.randint(1, 100)
gen = sensor()
print(next(gen))12. When to Use yield? 🎯
- When dealing with large datasets.
- When creating infinite sequences.
- When building custom iterators.
- When memory efficiency is required.
- When streaming data line-by-line.
Conclusion 🎉
yield transforms ordinary functions into powerful, memory-efficient iterators.” ✨You now fully understand the yield keyword! Want the next topic? Try Decorators, Iterators, Modules, or OOP (Classes & Objects). Just tell me! 😊