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@python
components: Documentation
messages: 259073
nosy: abarnert, docs@python
priority: normal
severity: normal
status: open
title: New misleading wording in execution model documenation

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue26225>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to