Re: exec and globals and locals ...

2019-09-20 Thread jfong
Peter Otten於 2019年9月20日星期五 UTC+8下午3時31分48秒寫道:
> jf...@ms4.hinet.net wrote:
> 
> >>>> x = 3
> >>>> def foo():
> > ... exec("print(globals(), locals()); x = x + 1; print(globals(),
> > locals())") ...
> >>>> foo()
> > {'foo': , '__package__': None, '__builtins__':
> > {, '__loader__':  > {'_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__name__':
> > {'__main__', '__spec__': None, 'x': 3} {} 'foo':  > {0x021C3468>, '__package__': None, '__builtins__':  > {(built-in)>, '__loader__': ,
> > {'__doc__': None, '__name__': '__main__', '__spec__': None, 'x': 3} {'x':
> > {4}
> >>>> def goo():
> > ... print(globals(), locals())
> > ... x = x + 1
> > ... print(globals(), locals())
> > ...
> >>>> goo()
> > {'foo': , '__package__': None, '__builtins__':
> > {, '__loader__':  > {'_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__name__':
> > {'__main__', '__spec__': None, 'goo': , 'x':
> > {3} {}
> > Traceback (most recent call last):
> >   File "", line 1, in 
> >   File "", line 3, in goo
> > UnboundLocalError: local variable 'x' referenced before assignment
> >>>>
> > 
> > Can't figure out what makes it different:-(
> 
> (0) exec() and class definitions use the LOAD_NAME opcode which looks into 
> the local namespace first and falls back to the global namespace. Therefore
> x = x may look up a global x and assign to a local one
> 
> The function body uses either 
> 
> (1) if there is a name binding operation (assignment, augmented assignment, 
> def, ...) LOAD_FAST which only looks into the local namespace. Thus
> x = x will only succeed if x is already defined in the local namespace.
> 
> (2) if there is no binding operation (name appears in an expression, x[...] 
> = ... or attribute assignment) LOAD_GLOBAL which only looks into the local 
> namespace.
> 
> Your first example is case 0, your second is case 1.

Hmm... exec() seems follow a more "LEGB" rule:-)

Thank you.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-20 Thread Peter Otten
jf...@ms4.hinet.net wrote:

>>>> x = 3
>>>> def foo():
> ... exec("print(globals(), locals()); x = x + 1; print(globals(),
> locals())") ...
>>>> foo()
> {'foo': , '__package__': None, '__builtins__':
> {, '__loader__':  {'_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__name__':
> {'__main__', '__spec__': None, 'x': 3} {} 'foo':  {0x021C3468>, '__package__': None, '__builtins__':  {(built-in)>, '__loader__': ,
> {'__doc__': None, '__name__': '__main__', '__spec__': None, 'x': 3} {'x':
> {4}
>>>> def goo():
> ... print(globals(), locals())
> ... x = x + 1
> ... print(globals(), locals())
> ...
>>>> goo()
> {'foo': , '__package__': None, '__builtins__':
> {, '__loader__':  {'_frozen_importlib.BuiltinImporter'>, '__doc__': None, '__name__':
> {'__main__', '__spec__': None, 'goo': , 'x':
> {3} {}
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "", line 3, in goo
> UnboundLocalError: local variable 'x' referenced before assignment
>>>>
> 
> Can't figure out what makes it different:-(

(0) exec() and class definitions use the LOAD_NAME opcode which looks into 
the local namespace first and falls back to the global namespace. Therefore
x = x may look up a global x and assign to a local one

The function body uses either 

(1) if there is a name binding operation (assignment, augmented assignment, 
def, ...) LOAD_FAST which only looks into the local namespace. Thus
x = x will only succeed if x is already defined in the local namespace.

(2) if there is no binding operation (name appears in an expression, x[...] 
= ... or attribute assignment) LOAD_GLOBAL which only looks into the local 
namespace.

Your first example is case 0, your second is case 1.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread jfong
>>> x = 3
>>> def foo():
... exec("print(globals(), locals()); x = x + 1; print(globals(), 
locals())")
...
>>> foo()
{'foo': , '__package__': None, '__builtins__': 
, '__loader__': , '__doc__': None, '__name__': '__main__', 
'__spec__': None, 'x': 3} {}
{'foo': , '__package__': None, '__builtins__': 
, '__loader__': , '__doc__': None, '__name__': '__main__', 
'__spec__': None, 'x': 3} {'x': 4}
>>> def goo():
... print(globals(), locals())
... x = x + 1
... print(globals(), locals())
...
>>> goo()
{'foo': , '__package__': None, '__builtins__': 
, '__loader__': , '__doc__': None, '__name__': '__main__', 
'__spec__': None, 'goo': , 'x': 3} {}
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 3, in goo
UnboundLocalError: local variable 'x' referenced before assignment
>>>

Can't figure out what makes it different:-(

--Jach

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
Am Donnerstag, 19. September 2019 20:24:49 UTC+2 schrieb Peter Otten:
> Eko palypse wrote:
> 
> > Am Donnerstag, 19. September 2019 18:31:43 UTC+2 schrieb Peter Otten:
> >> Eko palypse wrote:
> >> 
> >> > No, I have to correct myself
> >> > 
> >> > x = 5
> >> > def f1():
> >> > exec("x = x + 1; print('f1 in:', x)")
> >> > return x
> >> > print('f1 out', f1())
> >> > 
> >> > results in the same, for me confusing, results.
> >> > 
> >> > f1 in: 6
> >> > f1 out 5
> >> 
> >> Inside a function exec assignments go to a *copy* of the local namespace.
> >> Also LOAD_NAME is used to look up names. Therefore you can read and then
> >> shade a global name with its local namesake.
> >> 
> >> Inside a function the namespace is determined statically. As f1() has no
> >> assignment to x (code inside exec(...) is not considered) x is looked up
> >> in directly the global namespace using LOAD_GLOBAL.
> >> 
> >> If you want to access the local namespace used by exec() you have to
> >> provide one explicitly:
> >> 
> >> >>> x = 5
> >> >>> def f():
> >> ... ns = {}
> >> ... exec("x += 1", globals(), ns)
> >> ... return ns["x"]
> >> ...
> >> >>> f()
> >> 6
> >> >>> x
> >> 5
> >> 
> >> By the way, in Python 2 where exec was a statement the local namespace is
> >> shared:
> >> 
> >> >>> x = 5
> >> >>> def f():
> >> ... exec "x += 1"
> >> ... return x
> >> ...
> >> >>> f()
> >> 6
> >> >>> x
> >> 5
> > 
> > Sorry, missed that.
> > Thank you, may I ask you how I could have come myself
> > to that explanation? What do I have to read to get that understanding?
> > Hopefully you don't say read the C code, because that is something
> > I tried but failed miserably.
> 
> https://docs.python.org/3/library/functions.html#exec
> https://docs.python.org/3/reference/executionmodel.html#naming-and-binding
> 
> (I had to google for the second link.)
> 
> I usually experiment with code and the disassembler. I find its output quite 
> readable, 
> 
> >>> def f(): x += 1
> ... 
> >>> import dis
> >>> dis.dis(f)
>   1   0 LOAD_FAST0 (x)
>   3 LOAD_CONST   1 (1)
>   6 INPLACE_ADD
>   7 STORE_FAST   0 (x)
>  10 LOAD_CONST   0 (None)
>  13 RETURN_VALUE
> >>> dis.dis(compile("x += 1", "", "exec"))
>   1   0 LOAD_NAME0 (x)
>   3 LOAD_CONST   0 (1)
>   6 INPLACE_ADD
>   7 STORE_NAME   0 (x)
>  10 LOAD_CONST   1 (None)
>  13 RETURN_VALUE
> 
> and you can limit yourself to small snippets.

Thank you very much, really, very much appreciated.
Normally I do use docs.python.org as my first resource to look 
for an answer to my questions but I'm not always convinced that
my understanding/interpretation is correct.
Then I research on the web to see if there are similar questions and
try to understand these explanations but ...
and in this particular case I wasn't even able to find an answer. 

The dis module is nice to see differences but I assume more useful
to software developers than to hobby programmers like me.
At least not in the current state of knowledge I have.
I was under the impression that I have a good understanding of the 
python language before I started my current project but now ...
Enough whining :-)

Once again,
Thank you very much
Eren
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Peter Otten
Eko palypse wrote:

> Am Donnerstag, 19. September 2019 18:31:43 UTC+2 schrieb Peter Otten:
>> Eko palypse wrote:
>> 
>> > No, I have to correct myself
>> > 
>> > x = 5
>> > def f1():
>> > exec("x = x + 1; print('f1 in:', x)")
>> > return x
>> > print('f1 out', f1())
>> > 
>> > results in the same, for me confusing, results.
>> > 
>> > f1 in: 6
>> > f1 out 5
>> 
>> Inside a function exec assignments go to a *copy* of the local namespace.
>> Also LOAD_NAME is used to look up names. Therefore you can read and then
>> shade a global name with its local namesake.
>> 
>> Inside a function the namespace is determined statically. As f1() has no
>> assignment to x (code inside exec(...) is not considered) x is looked up
>> in directly the global namespace using LOAD_GLOBAL.
>> 
>> If you want to access the local namespace used by exec() you have to
>> provide one explicitly:
>> 
>> >>> x = 5
>> >>> def f():
>> ... ns = {}
>> ... exec("x += 1", globals(), ns)
>> ... return ns["x"]
>> ...
>> >>> f()
>> 6
>> >>> x
>> 5
>> 
>> By the way, in Python 2 where exec was a statement the local namespace is
>> shared:
>> 
>> >>> x = 5
>> >>> def f():
>> ... exec "x += 1"
>> ... return x
>> ...
>> >>> f()
>> 6
>> >>> x
>> 5
> 
> Sorry, missed that.
> Thank you, may I ask you how I could have come myself
> to that explanation? What do I have to read to get that understanding?
> Hopefully you don't say read the C code, because that is something
> I tried but failed miserably.

https://docs.python.org/3/library/functions.html#exec
https://docs.python.org/3/reference/executionmodel.html#naming-and-binding

(I had to google for the second link.)

I usually experiment with code and the disassembler. I find its output quite 
readable, 

>>> def f(): x += 1
... 
>>> import dis
>>> dis.dis(f)
  1   0 LOAD_FAST0 (x)
  3 LOAD_CONST   1 (1)
  6 INPLACE_ADD
  7 STORE_FAST   0 (x)
 10 LOAD_CONST   0 (None)
 13 RETURN_VALUE
>>> dis.dis(compile("x += 1", "", "exec"))
  1   0 LOAD_NAME0 (x)
  3 LOAD_CONST   0 (1)
  6 INPLACE_ADD
  7 STORE_NAME   0 (x)
 10 LOAD_CONST   1 (None)
 13 RETURN_VALUE

and you can limit yourself to small snippets.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
Am Donnerstag, 19. September 2019 18:31:43 UTC+2 schrieb Peter Otten:
> Eko palypse wrote:
> 
> > No, I have to correct myself
> > 
> > x = 5
> > def f1():
> > exec("x = x + 1; print('f1 in:', x)")
> > return x
> > print('f1 out', f1())
> > 
> > results in the same, for me confusing, results.
> > 
> > f1 in: 6
> > f1 out 5
> 
> Inside a function exec assignments go to a *copy* of the local namespace.
> Also LOAD_NAME is used to look up names. Therefore you can read and then 
> shade a global name with its local namesake.
> 
> Inside a function the namespace is determined statically. As f1() has no 
> assignment to x (code inside exec(...) is not considered) x is looked up in 
> directly the global namespace using LOAD_GLOBAL.
> 
> If you want to access the local namespace used by exec() you have to provide 
> one explicitly:
> 
> >>> x = 5
> >>> def f():
> ... ns = {}
> ... exec("x += 1", globals(), ns)
> ... return ns["x"]
> ... 
> >>> f()
> 6
> >>> x
> 5
> 
> By the way, in Python 2 where exec was a statement the local namespace is 
> shared:
> 
> >>> x = 5
> >>> def f():
> ... exec "x += 1"
> ... return x
> ... 
> >>> f()
> 6
> >>> x
> 5

Sorry, missed that. 
Thank you, may I ask you how I could have come myself
to that explanation? What do I have to read to get that understanding?
Hopefully you don't say read the C code, because that is something
I tried but failed miserably.

Thank you
Eren
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
First thank you for all the answers, very much appreciated.
I assume the root cause might be explained by the zen of python as well.

If the implementation is hard to explain, it's a bad idea.

Maybe I need to rethink my implementation :-)

Eren
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Peter Otten
Eko palypse wrote:

> No, I have to correct myself
> 
> x = 5
> def f1():
> exec("x = x + 1; print('f1 in:', x)")
> return x
> print('f1 out', f1())
> 
> results in the same, for me confusing, results.
> 
> f1 in: 6
> f1 out 5

Inside a function exec assignments go to a *copy* of the local namespace.
Also LOAD_NAME is used to look up names. Therefore you can read and then 
shade a global name with its local namesake.

Inside a function the namespace is determined statically. As f1() has no 
assignment to x (code inside exec(...) is not considered) x is looked up in 
directly the global namespace using LOAD_GLOBAL.

If you want to access the local namespace used by exec() you have to provide 
one explicitly:

>>> x = 5
>>> def f():
... ns = {}
... exec("x += 1", globals(), ns)
... return ns["x"]
... 
>>> f()
6
>>> x
5

By the way, in Python 2 where exec was a statement the local namespace is 
shared:

>>> x = 5
>>> def f():
... exec "x += 1"
... return x
... 
>>> f()
6
>>> x
5


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
No, I have to correct myself

x = 5
def f1():
exec("x = x + 1; print('f1 in:', x)")
return x
print('f1 out', f1())

results in the same, for me confusing, results.

f1 in: 6
f1 out 5

Eren
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Peter Otten
Eko palypse wrote:

> Thank you, I'm currently investigating importlib and read that
> __builtins__ might be another alternative.
> My ultimate goal would be to have objects available without the need to
> import them, regardless whether used in a script directly or used in an
> imported module.

I'm not sure this is a good idea. Or rather, I'm pretty sure this isn't a 
good idea ;)

To quote the Zen of Python

>>> import this
The Zen of Python, by Tim Peters
[...]
Namespaces are one honking great idea -- let's do more of those!

It looks like you are replacing that line with

"Let's put everything into builtins -- so convenient, no!"

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Peter Otten
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 "", line 1, in 
  File "", line 2, in f
UnboundLocalError: local variable 'x' referenced before assignment
>>> def g():
... x = x + 1
... 
>>> g()
Traceback (most recent call last):
  File "", line 1, in 
  File "", 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 "", line 1, in 
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 "", line 1, in 
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.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Bev In TX
I’m not the OP, but I want to thank you for that clarification.  I had 
previously not understood the ramifications of the following in section “7. 
Simple statements” in “The Python Language Reference”:

“An augmented assignment expression like x += 1 can be rewritten as x = x + 1 
to achieve a similar, but not exactly equal effect. In the augmented version, x 
is only evaluated once. Also, when possible, the actual operation is performed 
in-place, meaning that rather than creating a new object and assigning that to 
the target, the old object is modified instead.”

Thanks again.

Bev

> On Sep 19, 2019, at 5:45 AM, Richard Damon  wrote:
> 
> 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.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Richard Damon
On 9/19/19 6:52 AM, Eko palypse wrote:
> Am Donnerstag, 19. September 2019 12:45:35 UTC+2 schrieb Richard Damon:
>> 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.
>>
>> -- 
>> Richard Damon
> Thank you that would never have come to my mind.
> I thought +=1 is just syntactic sugar which clearly isn't.
> If I do the regular x = x + 1 then I do get the expected exception.
>
> Thank you
> Eren

For some objects, += even (possibly) calls a different function __radd__
instead of __add__ (if __radd__ doesn't exist then python will fall back
to using __add__)

This can have a big difference in the case of sharing mutable objects.

x = [1, 2]

y = x

x += [3]

# Now x and y are [1, 2, 3]

x = x + [4]

# Now x = [1, 2, 3, 4] but y is still [1, 2, 3]


-- 
Richard Damon

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
Am Donnerstag, 19. September 2019 12:56:59 UTC+2 schrieb Peter Otten:
> Eko palypse wrote:
> 
> >> Then it should be clear that the name 'test01' is put into globals(), if
> >> load_module() doesn't throw an exception. No sharing or nesting of
> >> namespaces takes place.
> > 
> > Thank you too for your answer. Ok, that means that in every case when exec
> > imports something it has its own global namespace, right?
> > Is there a way to manipulate this namespace before any code from that
> > module gets executed?
> 
> Create a module object, preload its namespace, then exec the module's code, 
> like:
> 
> $ python3
> Python 3.4.3 (default, Nov 12 2018, 22:25:49) 
> [GCC 4.8.4] on linux
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import sys, types
> >>> module = types.ModuleType("module")
> >>> module.x = 42
> >>> exec("print(x)\ndef f(): return x * x", module.__dict__)
> 42
> >>> sys.modules["module"] = module
> >>> import module
> >>> module.f()
> 1764
> 
> The importlib probably has an official way, but I've yet to wrap my head 
> around that part of Python.

Thank you, I'm currently investigating importlib and read that __builtins__
might be another alternative.
My ultimate goal would be to have objects available without the need to import 
them, regardless whether used in a script directly or used in an imported 
module.

Eren
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Peter Otten
Eko palypse wrote:

>> Then it should be clear that the name 'test01' is put into globals(), if
>> load_module() doesn't throw an exception. No sharing or nesting of
>> namespaces takes place.
> 
> Thank you too for your answer. Ok, that means that in every case when exec
> imports something it has its own global namespace, right?
> Is there a way to manipulate this namespace before any code from that
> module gets executed?

Create a module object, preload its namespace, then exec the module's code, 
like:

$ python3
Python 3.4.3 (default, Nov 12 2018, 22:25:49) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, types
>>> module = types.ModuleType("module")
>>> module.x = 42
>>> exec("print(x)\ndef f(): return x * x", module.__dict__)
42
>>> sys.modules["module"] = module
>>> import module
>>> module.f()
1764

The importlib probably has an official way, but I've yet to wrap my head 
around that part of Python.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
Am Donnerstag, 19. September 2019 12:45:35 UTC+2 schrieb Richard Damon:
> 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.
> 
> -- 
> Richard Damon

Thank you that would never have come to my mind.
I thought +=1 is just syntactic sugar which clearly isn't.
If I do the regular x = x + 1 then I do get the expected exception.

Thank you
Eren
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Richard Damon
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.

-- 
Richard Damon

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
> Then it should be clear that the name 'test01' is put into globals(), if 
> load_module() doesn't throw an exception. No sharing or nesting of 
> namespaces takes place.

Thank you too for your answer. Ok, that means that in every case when exec
imports something it has its own global namespace, right?
Is there a way to manipulate this namespace before any code from that module
gets executed? 

Eren
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Eko palypse
> 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
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-19 Thread Peter Otten
Eko palypse wrote:

> exec('import test01', globals())
> print('f3 out', x)
> 
> # result exception, expected but because f1 didn't throw an exception
> # I'm confused. module test01 has only this two lines
> x += 1
> print('f3 in:', x)

The lines above run in the test01's global namespace, not in the global 
namespace of the importing module.

> exec('import test01', globals())

Think of import as a function like

exec("test01 = load_module('test01')", globals())

Then it should be clear that the name 'test01' is put into globals(), if 
load_module() doesn't throw an exception. No sharing or nesting of 
namespaces takes place.


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: exec and globals and locals ...

2019-09-18 Thread dieter
Eko palypse  writes:
> Why does f1 work? I've expected an exception as no global dict has been 
> provided
> ...
>def f1(...):
>  exec("...")
>...

The documentation ("https://docs.python.org/3/library/functions.html#exec;)
tells you:

exec(object[, globals[, locals]])
...
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).

-- 
https://mail.python.org/mailman/listinfo/python-list


exec and globals and locals ...

2019-09-18 Thread Eko palypse
Why does f1 work? I've expected an exception as no global dict has been 
provided, and why does throw f3 an exception if it does, more or less, the same 
as f1?

x += 5
def f1():
exec("x += 1; print('f1 in:', x)")
return x
print('f1 out', f1())

# result => f1 in: 6
# result => f1 out 5


x = 5
def f2():
exec("x += 1; print('f2 in:', x)", globals())
return x
print('f2 out', f2())

# result => f2 in: 6
# result => f2 out 6


exec('import test01', globals())
print('f3 out', x)

# result exception, expected but because f1 didn't throw an exception 
# I'm confused. module test01 has only this two lines
x += 1
print('f3 in:', x)

Thank you
Eren
-- 
https://mail.python.org/mailman/listinfo/python-list