Python: exec() a code block and eval() the last line
<p>I have a string literal containing one or more lines of (trusted) Python code, and I would like to <code>exec()</code> the block, while capturing the results of the last line. More concretely, I would like a function <code>exec_then_eval</code> that returns the following:</p>

<pre><code>code = """
x = 4
y = 5
x + y
"""

assert exec_then_eval(code) == 9
</code></pre>

<p>A couple things I've tried:</p>

<ol>
<li><p>By splitting off the last line, you can exec the first block, then eval the last line; e.g.</p>

<pre><code>def exec_then_eval(code):
    first_block = '\n'.join(code.splitlines()[:-1])
    last_line = code.splitlines()[-1]
    globals = {}
    locals = {}
    exec(first_block, globals, locals)
    return eval(last_line, globals, locals)
</code></pre>

<p>This works, but will fail if the last statement has multiple lines.</p></li>
<li><p>If the code itself is modified so the result is stored as a local variable, this variable can then be recovered; e.g.</p>

<pre><code>code = """
x = 4
y = 5
z = x + y
"""

globals = {}
locals = {}
exec(code, globals, locals)
assert locals['z'] == 9
</code></pre>

<p>again, this works, but only if you're able to first parse the code block in a general way and modify it appropriately.</p></li>
</ol>

<p>Is there an easy way to write a general <code>exec_and_eval</code> function?</p>

<p>Based on @kalzekdor's suggestion of using the <code>ast</code> module, I came up with this solution which is similar in spirit to @vaultah's solution posted above:</p>

<pre><code>import ast

def exec_then_eval(code):
    block = ast.parse(code, mode='exec')

    # assumes last node is an expression
    last = ast.Expression(block.body.pop().value)

    _globals, _locals = {}, {}
    exec(compile(block, '&lt;string&gt;', mode='exec'), _globals, _locals)
    return eval(compile(last, '&lt;string&gt;', mode='eval'), _globals, _locals)
</code></pre>

<p>It also passes @vaultah's nice set of test-cases:</p>

<pre><code>exec_then_eval('''x = 4
y = 5
x + y''')) # 9

exec_then_eval('''x = 4
y = 5;x + y''')) # 9

exec_then_eval('''x = 4
y = 5;(
x + y *

2)''') # 14
</code></pre>

python