4 ms·
Note that `locals()` actually does funky things around enclosing scopes. Consider the following Python2/3 code: def outer(): x = 1 def inn
by rraval 12y ago
Note that `locals()` actually does funky things around enclosing scopes.
Consider the following Python2/3 code:
def outer():
x = 1
def inner():
print(x)
print("x = {x}".format(**locals()))
inner()
outer()
This actually prints the right thing when run:
1
x = 1
However, if you remove the `print(x)` line, both Python 2 and 3 don't hoist the enclosing `x` into `locals()` (since it can't see a single usage of that variable), resulting in a `KeyError`:
Traceback (most recent call last):
File "blah.py", line 7, in <module>
outer()
File "blah.py", line 5, in outer
inner()
File "blah.py", line 4, in inner
print("x = {x}".format(**locals()))
KeyError: 'x'
Python 3 has the `nonlocal` keyword that you can use to indicate that you're using a variable from an enclosing scope so that it's properly introduced into `locals()` but Python 2 doesn't have this facility.
- wylee 12y agoThat doesn't seem funky to me, given that `x` in your example is in fact not local to `inner`. It may seem surprising, but it's consistent with how Python handles locals in general.
- rraval 12y agoI called it funky because `x` is never local to `inner`, but gets an entry inside `locals()` if `inner` uses it implicitly or explicitly with `nonlocal`. Non-funky behaviour would be to have an `enclosing()` that walks up the outer functions and returns the union of their `locals()`. Alternatively, a `vars()` which expands to all variables in scope (respecting LEGB) would be best given the context of variable interpolation.