Boudewijn Rempt
|
Warning |
If you mess about with the globals and locals dictionary, be prepared to encounter what the Python Language Reference calls "undefined behavior". For instance, if you execute a bit of code with an empty locals dictionary, you cannot add new names to the namespace. This means that import won't work, for instance, or even variable assignments. Generally speaking, it is best to simply pass the globals dictionary, which means that the locals dictionary used by the executed code will be a copy of the globals dictionary. |
Let's compare these locals and globals from an interactive Python session:
Python 2.0 (#1, Mar 1 2001, 02:42:21) [GCC 2.95.2 19991024 (release)] on linux2 Type "copyright", "credits" or "license" for more information. >>> globals() {'__doc__': None, '__name__': '__main__', '__builtins__': <module '__builtin__' (built-in)>} >>> def f(): ... a=1 ... print "locals: ", locals() ... >>> globals() {'f': <function f at 0x8124a94>, '__doc__': None, '__name__': '__main__', '__builtins__': <module '__builtin__' (built-in)>} >>> f() locals: {'a': 1} >>>
First, we take a look at the contents of the globals dictionary when Python is first started. Then, we define a simple function f, that creates a variable a, which contains the value 1 and which prints the locals dictionary. Retrieving the value of globals shows that f is now part of globals. Running f shows that a is the only member of locals.
By default, the globals and locals arguments of eval(), exec() and execfile() contain the current contents of globals and locals, but you can alter this— for instance, to restrict access to certain application objects.
Playing with eval()
eval() functions as if it executes a single line of code in the Python interpreter: it returns a value that represents the result of the evaluated expression. If the statement you give to eval() raises an exception, the surrounding code gets that exception, too. Playing around with eval() will give you a feeling for what it can do for you.
Figure 20-1. Playing with eval()
boud@calcifer:~/doc/pyqt/ch15 > python Python 2.0 (#1, Mar 1 2001, 02:42:21) [GCC 2.95.2 19991024 (release)] on linux2 Type "copyright", "credits" or "license" for more information. >>> eval <built-in function eval> >>> eval("1==1") 1 >>> import string >>> eval("string.split('bla bla bla')") ['bla', 'bla', 'bla'] >>> eval("string.split('bla bla bla')", {}, {}) Traceback (most recent call last): File "<stdin>", line 1, in ? File "<string>", line 0, in ? NameError: There is no variable named 'string' >>> eval("""from qt import * ... s=QString("bla bla bla") ... print str(s).split() ... """) Traceback (most recent call last): File "<stdin>", line 1, in ? File "<string>", line 1 from qt import * ^ SyntaxError: invalid syntax >>>
First, we take a look at what "eval" is for a beast. A built-in function. OK, let's try it out. Yes, 1 equals 1 evaluates to 1, which means TRUE - eval neatly returns the result of the code it executes. Next, having imported the string module, we use it to split a string. Here, eval() has access to the global namespace, which means it can access the module we just imported, so string.split() evaluates just fine. However, if we try to evaluate the same expression, but with empty global and local dictionaries, we get a NameError exception - suddenly string isn't known anymore. Trying to evaluate something more complicated, something that is not a single expression that returns a value (even if it's only None) doesn't work at all - which is why exec() exists.
Playing with exec
First, exec is really a statement, not a function, so it doesn't return anything. Just as with eval(), exceptions are propagated outside the code block you execute. You can feed exec a string, a compiled code object or an open file. The file will be parsed until an EOF (end-of-file) occurs, and executed. The same rules hold for the global and local namespace dictionaries as with eval() - but keep in mind that running exec might add new items to those namespaces.
Figure 20-2. Playing with exec
boud@calcifer:~/doc/pyqt/ch15 > python Python 2.0 (#1, Mar 1 2001, 02:42:21) [GCC 2.95.2 19991024 (release)] on linux2 Type "copyright", "credits" or "license" for more information. >>> globals() {'__doc__': None, '__name__': '__main__', '__builtins__': <module '__builtin__' (built-in)>} >>> code = """ ... import qt ... s = qt.QString("bla bla bla") ... print string.split(str(s)) ... """ >>> exec code Traceback (most recent call last): File "<stdin>", line 1, in ? File "<string>", line 4, in ? NameError: There is no variable named 'string' >>> import string >>> exec code ['bla', 'bla', 'bla'] >>> globals() {'__doc__': None, 'string': <module 'string' from '/usr/lib/python2.0/string.pyc'>, '__name__': '__main__', '__builtins__': <module '__builtin__' (built-in)>, 'qt': <module 'qt' from '/usr/lib/python2.0/site-packages/qt.py'>, 'code': '\012import qt\012s = qt.QString("bla bla bla")\012print string.split(str(s))\012', 's': <qt.QString instance at 0x8278af4>} >>>
First, we create a string that contains the bit of Python we want to execute. Note how it imports the qt module, and how it uses the string module. Executing the code doesn't work: it throws a NameError because string isn't known. Importing string into the global namespace makes it also available to exec, of course. Executing the code string now succeeds, and a quick peek in globals learns us that the module qt has been added.
Playing with execfile()
The execfile() statement is rarely used; after all, it can't do anything beyond what the plain exec statement already does. execfile() functions exactly the same as exec, except that the first argument must be a filename (it doesn't need to be an open file object). Note that execfile() differs from import in that it doesn't create a new module in the global namespace. Note the difference between execfile() and import in the following output:
Figure 20-3. Playing with execfile()
Python 2.0 (#1, Mar 1 2001, 02:42:21) [GCC 2.95.2 19991024 (release)] on linux2 Type "copyright", "credits" or "license" for more information. >>> execfile("main.py") Initializing configuration {'kalam': <kalamapp.KalamApp instance at 0x825f014>, 'app': <qt.QApplication instance at 0x814a2a4>, 'args': ['']} Saving configuration >>> import main >>> globals() {..., 'main': <module 'main' from 'main.py'>, ... }
In the middle of all the qt classes the main module of Kalam imports into globals, we find the main module itself, which isn't there if we just execfile main.py.