Skip to main content

generator

Properties

>>> def gen():
... yield 1
... yield 2
>>> g = gen()
>>> [name for name in dir(g) if not name.startswith("__")]
['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']

Definition

A generator is an iterator created by a function that uses the yield keyword. Each yield pauses execution and produces a value; execution resumes from that point on the next iteration. Generators are single-use and lazy: values are produced on demand.

def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1

for num in count_up_to(3):
print(num) # 1 2 3

Creating generators

  • Generator function: any function containing yield.
  • Generator expression: (expr for item in iterable if condition).
# generator expression
>>> squares = (x*x for x in range(3))
>>> list(squares)
[0, 1, 4]

Using generators

Generators implement the iterator protocol and can be consumed with for, next, list(), or any function that takes an iterable.

g = count_up_to(2)
next(g) # 1
next(g) # 2
next(g) # StopIteration

Sending values in

send can inject a value into the generator, resuming it at the next yield expression.

def echo():
received = yield "ready"
yield received

g = echo()
next(g) # 'ready'
g.send("hi") # 'hi'

Throwing and closing

  • throw raises an exception inside the generator.
  • close raises GeneratorExit to stop the generator.
g = count_up_to(10)
next(g) # 1
g.close() # stops the generator

Dunder methods

Dunder MethodOperationExample (normal syntax)Example (dunder call)
__next__Get next valuenext(gen)gen.__next__()
__iter__Iterator protocolfor x in gengen.__iter__()
__send__Send a value ingen.send(10)gen.__send__(10)
__throw__Raise in generatorgen.throw(Exception)gen.__throw__(Exception)
__close__Stop generatorgen.close()gen.__close__()