exec and globals and locals ...

Peter Otten __peter__ at web.de
Fri Sep 20 03:31:09 EDT 2019


jfong at ms4.hinet.net wrote:

>>>> x = 3
>>>> def foo():
> ...     exec("print(globals(), locals()); x = x + 1; print(globals(),
> locals())") ...
>>>> foo()
> {'foo': <function foo at 0x021C3468>, '__package__': None, '__builtins__':
> {<module 'builtins' (built-in)>, '__loader__': <class
> {'_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__name__':
> {'__main__', '__spec__': None, 'x': 3} {} 'foo': <function foo at
> {0x021C3468>, '__package__': None, '__builtins__': <module 'builtins'
> {(built-in)>, '__loader__': <class '_frozen_importlib.BuiltinImporter'>,
> {'__doc__': None, '__name__': '__main__', '__spec__': None, 'x': 3} {'x':
> {4}
>>>> def goo():
> ...     print(globals(), locals())
> ...     x = x + 1
> ...     print(globals(), locals())
> ...
>>>> goo()
> {'foo': <function foo at 0x021C3468>, '__package__': None, '__builtins__':
> {<module 'builtins' (built-in)>, '__loader__': <class
> {'_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__name__':
> {'__main__', '__spec__': None, 'goo': <function goo at 0x021C3420>, 'x':
> {3} {}
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 3, in goo
> UnboundLocalError: local variable 'x' referenced before assignment
>>>>
> 
> Can't figure out what makes it different:-(

(0) exec() and class definitions use the LOAD_NAME opcode which looks into 
the local namespace first and falls back to the global namespace. Therefore
x = x may look up a global x and assign to a local one

The function body uses either 

(1) if there is a name binding operation (assignment, augmented assignment, 
def, ...) LOAD_FAST which only looks into the local namespace. Thus
x = x will only succeed if x is already defined in the local namespace.

(2) if there is no binding operation (name appears in an expression, x[...] 
= ... or attribute assignment) LOAD_GLOBAL which only looks into the local 
namespace.

Your first example is case 0, your second is case 1.




More information about the Python-list mailing list