osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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_FAST                0 (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", "<nofile>", "exec"))
>   1           0 LOAD_NAME                0 (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