Python provides the following three built-in functions to manually execute, evaluate, and compile arbitrary Python code:
- exec(object, globals, locals): This allows you to dynamically execute the Python code. object should be a string or code object (see the compile() function) representing a single statement or sequence of multiple statements. The globals and locals arguments provide global and local namespaces for the executed code and are optional. If they are not provided, then the code is executed in the current scope. If provided, globals must be a dictionary, while locals might be any mapping object; it always returns None.
- eval(expression, globals, locals): This is used to evaluate the given expression by returning its value. It is similar to exec(), but it expects expression to be a single Python expression and not a sequence of statements. It returns the value of the evaluated expression.
- compile(source, filename, mode): This compiles the source into the code object or AST object. The source code is provided as a string value in the source argument. The filename should be the file from which the code was read. If it has no file associated (for example, because it was created dynamically), then <string> is the value that is commonly used. Mode should be either exec (sequence of statements), eval (single expression), or single (a single interactive statement, such as in a Python interactive session).
The exec() and eval() functions are the easiest to start with when trying to dynamically generate code because they can operate on strings. If you already know how to program in Python, then you may already know how to correctly generate working source code programmatically.
The most useful in the context of metaprogramming is obviously exec() because it allows you to execute any sequence of Python statements. The word any should be alarming for you. Even eval(), which allows only evaluation of expressions in the hands of a skillful programmer (when fed with the user input), can lead to serious security holes. Note that crashing the Python interpreter is the scenario you should be least afraid of. Introducing vulnerability to remote execution exploits due to irresponsible use of exec() and eval() can cost you your image as a professional developer, or even your job.
Even if used with a trusted input, there is a list of little details about exec() and eval() that is too long to be included here, but might affect how your application works in ways you would not expect. Armin Ronacher has a good article that lists the most important of them, titled Be careful with exec and eval in Python (refer to http://lucumr.pocoo.org/2011/2/1/exec-in-python/).
Despite all these frightening warnings, there are natural situations where the usage of exec() and eval() is really justified. Still, in the case of even the tiniest doubt, you should not use them and try to find a different solution.
The signature of the eval() function might make you think that if you provide empty globals and locals namespaces and wrap it with proper try ... except statements, then it will be reasonably safe. There could be nothing more wrong. Ned Batcheler has written a very good article in which he shows how to cause an interpreter segmentation fault in the eval() call, even with erased access to all Python built-ins (see http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html). This is single proof that both exec() and eval() should never be used with untrusted input.
We'll take a look at abstract syntax tree in the next section.