-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Compiling Nested Functions
Nested functions can access variables defined in an outer function:
def f(x: int) -> None:
def g() -> None:
print(x) # Refer to x in the outer function
g()
To support this, mypyc creates a hidden environment class, and instances of this class hold locals that are accessed in nested functions. The nested function is also represented as an instance of a generated class which has a reference to the environment. The example above behaves like this when compiled, roughly:
class f_env: # Generated class, implementation detail
x: int
g: g_f_obj
class g_f_obj: # Generated class, implementation detail
__mypyc_env__: f_env
def __call__(self) -> None:
print(self.__mypyc_env__.x)
def f(x: int) -> None:
_env = f_env()
_env.x = x
g = g_f_obj()
g.__mypyc_env__ = _env
_env.g = g
g()
The environment class _env
also holds a reference to the nested function g
to allow recursive calls in g
, and mutually recursive calls if there are multiple nested functions. The nested function has no direct access to the locals of the outer function. In this case there are no recursive calls so we could drop the g
attribute. It's sometimes needed and we generate it always, just in case.
The environment and the nested function object are separate instances so that locals can be shared between multiple nested functions. If there was only a single nested function, we could merge the environment and the function object.
-
mypyc/irbuild/envclass.py
(environment classes) -
mypyc/irbuild/callable_class
(nested function objects)