diveintopython.org
Python for experienced programmers

 

2.5. Executing code dynamically

Python has the ability to execute arbitrary strings as Python code. This means that you can build code dynamically as strings and then execute it, just as if you had typed it in before running the program.

Many other scripting languages can do this, including Perl, JavaScript, and Transact/SQL in SQL Server. But there are differences in Python's implementation, especially compared to Transact/SQL, so watch closely.

Example 2.11. Using exec

    if type(object) == ModuleType:
        name = object.__name__
        exec("import %s" % name)

The exec function, in its simplest form, takes a string and executes it as Python code in the current content. That means that this code will import the module called name and make available all its attributes and methods, just as if you had coded an import statement with the name directly. But of course you couldn't have done that, because you didn't know the name before you ran the program.

Example 2.12. Accessing variables within exec

>>> x = 1
>>> exec("print x") 1
1
>>> exec("x = 2")   2
>>> print x         3
2
1 This is the part that SQL Server script kiddies will find bizarre. You might expect this to cause an error because x is not defined within the exec statement. But in Python, the statement is execed in the current context, so it has access to variables “outside” the exec.
2 Since execed statements are executed in the current context, this statement does not create a new variable called x; it changes the value of the existing variable outside the exec statement.
3 The value of x is now 2, because it was set in the execed statement. Note that there is no way to tell what changes took place within an exec call and which occurred in “normal” code; as far as Python is concerned, it's all just code.

A complementary function to exec is eval. While exec executes a command, eval evaluates an expression and returns its value. Of course, some expressions (like list.pop()) have side effects, but generally you will use eval strictly for the expression's return value.

Example 2.13. Introducing eval

>>> x = 1
>>> y = 2
>>> s = "x"
>>> eval(s) 1
1
>>> s = "y*2"
>>> eval(s) 2
4
>>> s = "s"
>>> eval(s) 3
's'
1 s is a string whose value is "x", so this is equivalent to eval("x"), which evaluates the expression x, which is 1.
2 s is a string whose value is "y*2", so this is equivalent to eval("y*2"), which evaluates the expression y*2, which is 2*2, which is 4.
3 s is a string whose value is s, so this is equivalent to eval("s"), which evaluates the expression s, which is 's'. Note that although this is self-referencing, it is not infinitely recursively self-referencing.

Example 2.14. Using eval in apihelper.py

>>> import odbchelper
>>> name = "odbchelper"
>>> e = "buildConnectionString"
>>> "%s.%s" % (name, e)              1
'odbchelper.buildConnectionString'
>>> eval("%s.%s" % (name, e))        2

>>> func = eval("%s.%s" % (name, e)) 3
>>> func({"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"})
'server=mpilgrim;uid=sa;database=master;pwd=secret'
1 This is not new; this is just basic string formatting.
2 This is equivalent to eval("odbchelper.buildConnectionString"), which evaluates to an object, the function buildConnectionString in the module odbchelper. Did I mention that everything in Python is an object?
3 You can assign the return value of eval to a variable or do whatever else you want with it. In this case, you can use it to call the buildConnectionString function just as if you were calling it directly. You can also access the function's attributes, like its doc string, as we'll see shortly.