Control a generator interactively through send(), throw(), and close().
What You Will Learn
send(value) resumes a suspended generator and supplies a value to its current yield expression; prime with next() or send(None) first. throw(exception) injects an exception into the generator; close() requests termination through GeneratorExit.
Generator.throw() may be used for error propagation but modern code often prefers explicit async or iterator APIs.
Many iterator tools are lazy. Creating the iterator does not necessarily perform the work; advancing it can consume the original source.
Step-by-Step Example
The example below makes the behavior visible with small input values that you can change safely.
def running_total():
total = 0
try:
while True:
try:
added_value = yield total
except ValueError:
print("Invalid value ignored")
continue
if added_value is not None:
total += added_value
finally:
print("Generator closed")
calculator = running_total()
print(next(calculator))
print(calculator.send(5))
print(calculator.throw(ValueError("invalid data")))
print(calculator.send(3))
calculator.close()
How the Example Works
- The function running_total defines reusable behavior; its body executes when it is called, not when it is declared.
- The variable calculator holds the result of running_total(). Later lines use that value or inspect how it changes.
- The print() calls make the return values or state visible so you can compare them with the explanation and check your prediction.
Expected output from the example:
0
5
Invalid value ignored
5
8
Generator closed
When You Would Use This
This pattern is useful in readers for CSV files, event streams, or paginated API results, where collecting everything in memory is unnecessary. Because iterator state advances when values are consumed, decide whether you need a reusable collection or a one-time pass. Keep files and connections open until their lazy consumers finish.
Practice: Modify the Code
Add a validation rule for negative sent values and inject a test exception with throw().
Verify the changed output against the behavior described above, including the relevant invalid or boundary case.
For complete parameters and version details, consult the official Python documentation.
Common Beginner Mistakes
- Calling send(non_none_value) before starting a newly created generator.
- Catching GeneratorExit and then yielding another value during close(), which raises RuntimeError.
Key Takeaways
- Control a generator interactively through send(), throw(), and close().
- send(value) resumes a suspended generator and supplies a value to its current yield expression; prime with next() or send(None) first. throw(exception) injects an exception into the generator; close() requests termination through GeneratorExit.
- Generator.throw() may be used for error propagation but modern code often prefers explicit async or iterator APIs.