Uzytkownik "Steven Bethard" <[EMAIL PROTECTED]> napisal w wiadomosci news:[EMAIL PROTECTED]
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 -- http://mail.python.org/mailman/listinfo/python-list