exec and globals and locals ...
Peter Otten
__peter__ at web.de
Thu Sep 19 09:33:44 EDT 2019
Richard Damon wrote:
> On 9/19/19 6:16 AM, Eko palypse wrote:
>>> In all cases, if the optional parts are omitted, the code is executed in
>>> the current scope. ...
>>>
>>>
>>> You can see from it that "globals" is optional.
>>> And that, if "globals" is missing, then
>>> "exec" is executed in the current scope ("f1" in your case).
>> Thank you for your answer, and that is exactly what confuses me?
>> Where does x come from? If I only would read x then I would understand
>> why it can be found/read but I alter it and as such I either have to
>> provide the info that this is a global variable, declare it inside of f1
>> or provide the globals dict to exec. But I don't do any of it. Why is
>> exec able to use the global x?
>>
>> Eren
>
> I think the issue is that x += 1 isn't exactly like x = x + 1, and this
> is one case that shows it. x = x + 1 is an assignment to the symbol x,
> which makes x a local, and thus the read becomes an undefined symbol. x
> += 1 is different, it isn't a plain assignment so doesn't create the
> local. The read of x is inherently tied to the writing of x so x stays
> referring to the global.
I think you are wrong; both x += 1 and x = x + 1 turn x into a local
variable:
>>> def f():
... x += 1
...
>>> x = 42
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UnboundLocalError: local variable 'x' referenced before assignment
>>> def g():
... x = x + 1
...
>>> g()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in g
UnboundLocalError: local variable 'x' referenced before assignment
The difference is that
x = x + 1
is evaluated as
x = x.__add__(1)
while x += 1 becomes
x = x.__iadd__(1)
For mutable x this allows modifying x in place with consequences likely to
surprise when you see it for the first time:
>>> t = ["Nobody expects "],
>>> t[0] = t[0] + ["the Spanish inquisition"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(['Nobody expects '],)
The above creates a new list which cannot become the first item of the
(immutable) tuple.
>>> t[0] += ["the Spanish inquisition"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
The above changes the first item of the tuple in place, but afterwards the
attempt to rebind t[0] still fails.
More information about the Python-list
mailing list