How to eval a multiple line “function” in Python

Python has two basic methods of evaluating Python code: eval and exec. eval will only accept a single statement, while exec doesn’t allow return statements — that is, unless you wrap your code in a function definition…

Crux in red:

import re
import sys

def eval_as_function(code, local_vars = None, global_vars = None):
    if local_vars is None:
        local_vars = {}
    if global_vars is None:
        global_vars = globals()
    retval = None
        context = {}
        code = re.sub(r"(?m)^", "    ", code)
        code = "def anon(" + ','.join(local_vars.keys()) + "):\n" + code
        exec code in global_vars, context
        retval = context['anon'](*(local_vars.values()))
        print "an error occurred in eval_a_function:"
        print str(sys.exc_info()) + "\n\n"
        print "in this code:\n\n" + code + "\n\n"
    return retval

code = """
if foo == 'bar':
    return True
"""[1:-1] # strip blank lines

print eval_as_function(code, { 'foo': 'bar' })

The usual caution about evaluating untrusted strings applies, but also note that the keys of local_vars are evaluated as the anonymous function argument names.

Improvements welcome! :)


One response to this post.

  1. Posted by Gero Gozco on March 3, 2015 at 9:02 am

    Line 12 -> re.sub(r”(?m)^”, ” “, code)


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: