Re: exec and globals and locals ...
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 ...
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 ...
>>> 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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
> 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 ...
> 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 ...
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 ...
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 ...
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