func_code vs. string problem
Steven Bethard
steven.bethard at gmail.com
Sat Apr 23 18:13:40 EDT 2005
Filip Dreger wrote:
> Uzytkownik "Steven Bethard" <steven.bethard at gmail.com> napisal w
> wiadomosci news:04mdnXLeedaPLvffRVn-vQ at comcast.com...
>
>>See the documentation:
>>
>>http://docs.python.org/ref/dynamic-features.html
>>
>>"""The eval(), execfile(), and input() functions and the exec
>>statement do not have access to the full environment for resolving
>>names. Names may be resolved in the local and global namespaces of
>>the caller. Free variables are not resolved in the nearest enclosing
>>namespace, but in the global namespace."""
>
> Thank you! I feel silly I have not found the piece of instruction
> myself. And even worse, as I still do not understand: if exec()
> resolves free bariable names in the global namespace, how come it
> works well with code in a string? Or with a code in a compiled string?
Well, probably the best thing to do is to check out what byte-code is
generated in each case:
py> s = compile('print b', 'string', 'exec')
py> def f():
... print b
...
py> import dis
py> dis.dis(s)
1 0 LOAD_NAME 0 (b)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
py> dis.dis(f)
2 0 LOAD_GLOBAL 0 (b)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
So, the code is basically identical, except that with the string, the
code uses LOAD_NAME, while with the function, the code uses LOAD_GLOBAL.
Note that this is because Python can tell that b is not defined in the
function, and so it assumes that is must be a global lookup. Look what
happens if I give f a parameter:
py> def f(b):
... print b
...
py> dis.dis(f)
2 0 LOAD_FAST 0 (b)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
Now f is using LOAD_FAST, which looks at the locals. I believe the
point of LOAD_GLOBAL and LOAD_FAST (instead of always using LOAD_NAME)
is to increase performance in the common case, where exec is not used.
Seems like the documentation is being a little conservative -- it does
look like some statements will do the lookup in the locals too... If I
was more confident about what goes on here, I'd probably try to file a
documentation bug...
> The manual says I can pass two dictionaries to exec, one for global
> namespace and one for local. But, strange as it seems, I could not get
> it to work. In the example I gave, changing exec f.func_code to exec
> f.func_code in globals(),locals() does not help a bit.
That's because, as the dis.dis output above shows, the function you've
defined is only searching the global namespace. So the locals() dict
you pass won't ever be looked at.
[snip example using locals as globals]
>
> I thought about that... I don't know why, but it seems wrong. Maybe
> the updating dictionaries is not very expensive, but there must be
> some better way. This code has a 'workaround - fixme' written all over
> it.
Yeah, I agree. On the other hand, whenever I see exec, it has
'workaround - fixme' written all over it too. ;)
STeVe
More information about the Python-list
mailing list