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 steven.daprano
Recipients eryksun, qpeter, steven.daprano
Date 2021-12-23.04:33:58
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <20211223043030.GQ6272@ando.pearwood.info>
In-reply-to <1640218529.25.0.509294318437.issue46153@roundup.psfhosted.org>
Content
On Thu, Dec 23, 2021 at 12:15:29AM +0000, Eryk Sun wrote:
> 
> Eryk Sun <eryksun@gmail.com> added the comment:
> 
> > If exec gets two separate objects as globals and locals, 
> > the code will be executed as if it were embedded in a 
> > class definition.
> 
> That's a misleading comparison 

That's taken straight out of the documentation.

I don't think it is misleading, it is the opposite of misleading. Until 
I understood that exec with two different mapping objects as globals and 
locals behaves as if the code where embedded inside a class, I found the 
reported behaviour totally perplexing.

If you think it is wrong, how would you explain the observed behaviour, 
and how would you word the documentation?

> because a class definition intentionally supports nonlocal closures, 

I don't know what you mean by that. Classes are never closures. Only 
functions can be closures. (*Be* closures? *Have* a closure? The 
terminology is ambiguous.)

>>> def f():
...     a = 1
...     class C:
...             nonlocal a
...             a = 999
...     print(a)
...     return C
... 
>>> C = f()
999
>>> C.__closure__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute '__closure__'. Did you mean: '__module__'?

I don't know what terminology is appropriate here, but "closure" is 
surely not it.

> which exec() doesn't support and shouldn't support. For example:
[snip examples]

Neither of those cases are relevant to the example here.

> exec() executes as module code. Using separate globals and locals 
> mappings doesn't magically change how the code is compiled and 
> executed to make it equivalent to a class definition.

Neither I nor the documentation said it was equivalent to a class 
definition. It is equivalent to code executed inside a class scope.

> To understand 
> the case of separate globals and locals, just remember that assigning 
> to a variable by default makes it a local variable, unless it's 
> declared as a global. Also, class and function definitions are 
> implicitly an assignment, which by default will be local.

Neither of those facts explain why the example code

    """a = 1
    def f():
        return a
    print(f())
    """

behaves differently when given two distinct dicts as the globals and 
locals parameters, versus all the other cases (no arguments provided, or 
one argument, or the same dict repeated twice).

Only the case where the provided globals and locals dicts are distinct 
behaves differently, and it behaves exactly the same as if you embedded 
that chunk of code inside a class definition and then executed it.
History
Date User Action Args
2021-12-23 04:33:59steven.dapranosetrecipients: + steven.daprano, eryksun, qpeter
2021-12-23 04:33:59steven.dapranolinkissue46153 messages
2021-12-23 04:33:58steven.dapranocreate