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 abarnert
Recipients abarnert, docs@python
Date 2016-01-28.00:01:28
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1453939288.53.0.211010759952.issue26225@psf.upfronthosting.co.za>
In-reply-to
Content
In #24129, the wording describing class local bindings in 4.2.2 "Resolution of names" was changed for Python 3.4, 3.5, and 3.6. The new version is a lot clearer for classes--but now it's misleading for `exec`/`eval`.

---

> Class definition blocks and arguments to exec() and eval() are
> special in the context of name resolution. A class definition is...

... and then proceeds to explain how class lookup works, without ever mentioning `exec` and `eval`. This implies that they work the same way as classes, but of course that's not true:

    i = 'global'
    def f():
        i = 'nonlocal'
        class C:
            print(i)
            i = 'local'
            print(i)
    f()

That prints `global`, then `local`. But with `exec`:

    i = 'global'
    def f():
        i = 'nonlocal'
        exec("print(i)\ni = 'local'\nprint(i)\n")
    f()

That prints `nonlocal` then `local`.

I think just putting a paragraph break between the first sentence and the rest of the paragraph might be sufficient to avoid the confusion here. Or just removing any mention of `eval` and `exec`. If not, this probably needs a new one-liner paragraph saying something like "Arguments to `exec()` and `eval()` are also special, as described later."

---

Meanwhile, if you keep reading, you'll eventually find that `exec` is described in a later section, 4.2.4 "Interaction with dynamic features", but that's _also_ misleading:

> The eval() and exec() functions do not have access to the full
> environment for resolving names. Names may be resolved in the
> local and global namespaces of the caller. Free variables are not
> resolved in the nearest enclosing namespace, but in the global
> namespace.

If that were true, the `exec` example would have printed `global`, right?

I'm pretty sure that what's going on here is that `exec` implicitly calls `locals()` (or, rather, the C-API equivalent), which constructs a locals dict on demand, which, only if you're inside a function block, includes not just the currently-bound fast locals, but _also_ the cell_contents of the currently-bound free variables. So, as far as `exec` is concerned, `i` is not an unbound local, or a free variable, but a local, which is bound to the `'nonlocal'` cell value of `i` at the time `exec` was called.

Which means the following actually _does_ print `global`:

    i = 'global'
    def f():
        exec("print(i)\ni = 'local'\nprint(i)\n")
        i = 'nonlocal'
    f()

I have no idea how to make this clear. Maybe the simplest is to not try to give a full explanation here, and instead punt to the `locals()` function definition? Maybe something like this:

> The `eval()` and `exec()` functions do not have access to the full environment for resolving names, but rather to the approximation of that environment as constructed by the `locals()` function. Free variables that are not captured as locals are not resolved in the nearest enclosing namespace, but in the global...

... and from there, the same as the current paragraph.
History
Date User Action Args
2016-01-28 00:01:28abarnertsetrecipients: + abarnert, docs@python
2016-01-28 00:01:28abarnertsetmessageid: <1453939288.53.0.211010759952.issue26225@psf.upfronthosting.co.za>
2016-01-28 00:01:28abarnertlinkissue26225 messages
2016-01-28 00:01:28abarnertcreate