This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author martin.panter
Recipients abarnert, docs@python, eryksun, martin.panter
Date 2016-01-30.05:14:18
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1454130859.83.0.483569917515.issue26225@psf.upfronthosting.co.za>
In-reply-to
Content
Calling exec() with only one argument is equivalent to exec(..., globals(), locals()). It does not create a new scope for names. So an equivalent of your three-level example is more like

>>> i = 'global'
>>> def f():
...     i = 'nonlocal'
...     class_locals = dict()
...     exec("print(i)\ni = 'local'\nprint(i)\n", globals(), class_locals)
... 
>>> f()
global
local

If exec() worked like a function rather than a class, the first print(i) would trigger an UnboundLocalError instead:

>>> i = 'global'
>>> def f():
...     i = 'nonlocal'
...     def g():
...         print(i)
...         i = 'local'
...     g()
... 
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in f
  File "<stdin>", line 4, in g
UnboundLocalError: local variable 'i' referenced before assignment

In your first exec() example, i='nonlocal' is passed to exec() via the default locals parameter, and the exec() uses that value rather than deferring to its globals. To be a free variable, “i” has to be used but not defined. Even if you dropped the “i = 'local' ” assignment, it is still defined via the implicit locals parameter.

Your proposal for “Interaction with dynamic features” sounds reasonable.
History
Date User Action Args
2016-01-30 05:14:19martin.pantersetrecipients: + martin.panter, docs@python, eryksun, abarnert
2016-01-30 05:14:19martin.pantersetmessageid: <1454130859.83.0.483569917515.issue26225@psf.upfronthosting.co.za>
2016-01-30 05:14:19martin.panterlinkissue26225 messages
2016-01-30 05:14:18martin.pantercreate