-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Compiling Generators
Jukka Lehtosalo edited this page Oct 25, 2022
·
3 revisions
Generator functions must maintain state between invocations. A generator function is compiled into two classes. One is an environment class that maintains the local variables of the function, and the label/location where execution will continue
(__mypyc_next_label__
attribute). The second class implements the actual generator. The environment class is similar to what mypyc uses to support nested functions.
For example, consider this simple generator:
def f(x: int) -> Iterator[int]:
print('a')
yield x
print('b')
This is compiled to something roughly like this (in heavily simplified pseudo-python):
def f(x: int) -> Iterator[int]:
_env = f_env()
_env.x = x
_env.__mypyc_next_label__ = 0
_gen = f_gen()
_gen.__mypyc_env__ = _env
return _gen
class f_env:
x: int
__mypyc_next_label__: int
class f_gen:
__mypyc_env__: f_env
def __next__(self) -> int:
_env = self.__mypyc_env__
_label = _env.__mypyc_next_label__
if _label == 0:
print('a')
_ret = _env.x
_env.__mypyc_next_label__ = 1
return _ret
elif _label == 1:
print('b')
_env.__mypyc_next_label__ = -1
raise StopIteration()
else:
raise StopIteration() # Already completed
The actual generated code is more complicated because of error handling, and close
/throw
/send
methods.