I am trying to figure out how an inner function, that is a constant, becomes a cell variable. Furthermore, how does it get looked up?
Consider my example:
>>> def outer():
... def inner(x):
... if x <= 0:
... return 0
... else:
... return x + inner(x-1)
... return inner(3)
...
>>>
>>> outer()
6
>>> outer.__code__.co_cellvars
('inner',)
>>> outer.__code__.co_consts
(None, <code object inner at 0x0000022FBC03E2F0, file "<stdin>", line 2>, 'outer.<locals>.inner', 3)
>>> outer.__code__.co_consts[1].co_freevars
('inner',)
This is a common pattern for me for recursive functions. There is an outer function that sets up some initial conditions for an inner function that does the actual recursion.
Presumably while generating bytecode, the Python runtime is able to walk up the potential frames and find that recursing inner() references a constant contained in outer().
I was thinking maybe outer turns it in a local, but I was sabotaged:
>>> def outer():
... print(locals())
... def inner(x):
... if x <= 0:
... return 0
... else:
... return x + inner(x-1)
... return inner(3)
...
>>>
>>> outer()
{}
6
I’m trying to mimic the proper behavior in a personal Python interpreter project and I can’t figure out all the plumbing. Like, I detect the name “inner” and I find it in the constants for “outer” but I can’t tell what the right thing to do is with that information–especially when I get to actually running the LOAD_DEREF it takes to find inner() at run time.