[New-bugs-announce] [issue26225] New misleading wording in execution model documenation

Andrew Barnert report at bugs.python.org
Wed Jan 27 19:01:28 EST 2016


New submission from Andrew Barnert:

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.

----------
assignee: docs at python
components: Documentation
messages: 259073
nosy: abarnert, docs at python
priority: normal
severity: normal
status: open
title: New misleading wording in execution model documenation

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue26225>
_______________________________________


More information about the New-bugs-announce mailing list