In Python, the yield
keyword is used to create a generator function, which produces a sequence of values lazily (on-demand) instead of returning them all at once. It allows you to pause and resume the function’s execution, retaining its state between successive calls. This is especially useful for handling large datasets or infinite sequences efficiently.
Key Behaviors of yield
:
- Lazy Evaluation: Values are generated one at a time, reducing memory usage.
- State Preservation: The function’s state (variables, execution point) is saved between
yield
calls. - Iteration Support: Generators implement the iterator protocol and work with loops (
for
,next()
).
Example 1: Simple Generator
python
def count_up_to(n):
count = 1
while count <= n:
yield count # Pauses here and returns `count`
count += 1
# Create a generator object
generator = count_up_to(3)
# Iterate using next()
print(next(generator)) # Output: 1
print(next(generator)) # Output: 2
print(next(generator)) # Output: 3
# print(next(generator)) # Raises StopIteration
# Or use in a loop
for num in count_up_to(5):
print(num) # Output: 1, 2, 3, 4, 5
Example 2: Infinite Sequence
Generators can model infinite sequences without memory overhead:
python
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# Print the first 5 Fibonacci numbers
fib_gen = fibonacci()
for _ in range(5):
print(next(fib_gen)) # Output: 0, 1, 1, 2, 3
Example 3: Sending Values to a Generator
Use send()
to pass values back into the generator:
python
def echo():
response = yield "Ready?" # Yield initial message and wait for input
while True:
response = yield f"You said: {response}"
gen = echo()
print(next(gen)) # Output: "Ready?"
print(gen.send("Hello")) # Output: "You said: Hello"
print(gen.send("Bye")) # Output: "You said: Bye"
Key Use Cases:
- Large Data Processing: Stream data without loading it all into memory.
- Stateful Iteration: Maintain context between iterations (e.g., parsers, pipelines).
- Coroutines: Implement cooperative multitasking (e.g., with
asyncio
).
How It Works:
- When a generator function is called, it returns a generator object (but doesn’t execute immediately).
- On calling
next()
orsend()
, the function runs until it hitsyield
, emits a value, and pauses. - The next call resumes execution immediately after the
yield
statement.
Comparison with return
:
yield | return |
---|---|
Produces a generator | Terminates function |
Can yield multiple values | Returns once |
Retains state between calls | Resets state |
By leveraging yield
, you write memory-efficient, scalable code for sequential data processing.