exec and globals and locals ...

jfong at ms4.hinet.net jfong at ms4.hinet.net
Fri Sep 20 04:28:25 EDT 2019


Peter Otten於 2019年9月20日星期五 UTC+8下午3時31分48秒寫道:
> 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.

Hmm... exec() seems follow a more "LEGB" rule:-)

Thank you.



More information about the Python-list mailing list