A generator preserves a suspended frame between yields, and send supplies the value received by its current yield expression.
Python generator send and close: suspension retains state until cleanup
Operation contract
The running-total generator emits its current total before accepting another amount. next primes the first suspension point; send then validates and incorporates the received amount before yielding again. An invalid amount exits the generator through ValueError and executes its finally block. A second generator is closed explicitly after priming. Neither path publishes the partially accepted state to an external ledger.
Failure and ownership boundary
A non-None value cannot be sent into a generator that has not reached its first yield. close requests termination at the suspension point; cleanup must not try to yield another value in response. Python generators: lazy iteration does not make retained output free, Python context managers: clean up on success and failure and Python async generators: close a suspended producer when leaving early use related lifetime rules, but they are not interchangeable APIs.
Working program
closed = []
def running_total():
total = 0
try:
while True:
amount = yield total
if type(amount) is not int or not 0 <= amount <= 1000:
raise ValueError("bounded exact amount required")
total += amount
finally:
closed.append("released")
producer = running_total()
print("initial:", next(producer))
print("accepted:", producer.send(125))
try:
producer.send(True)
except ValueError:
print("invalid send rejected")
print("closed:", closed)
second = running_total()
next(second)
second.close()
print("explicit closes:", len(closed))Output
initial: 0
accepted: 125
invalid send rejected
closed: ['released']
explicit closes: 2Costs and limits
A suspended frame retains its locals and reachable objects. This generator has constant-sized application state, except for growing integer digit length and the demonstration cleanup list. A producer owning a file or cursor needs explicit caller cleanup when iteration ends early.
Common Mistakes
- Prime a generator before sending a non-None value.
- Do not assume an early loop break closes a retained generator.
Connected lessons
Python generators: lazy iteration does not make retained output free, Python iterators: exhaustion and repeatable collection ownership, Python async generators: close a suspended producer when leaving early.
