2016-09-07 40 views
5

我有一個包含一行或多行(可信)Python代碼的字符串,我想exec()該塊,同時捕獲結果最後一行。更具體地說,我想一個函數exec_then_eval返回以下內容:Python:exec()代碼塊和eval()最後一行

code = """ 
x = 4 
y = 5 
x + y 
""" 

assert exec_then_eval(code) == 9 

有兩件事情我已經試過:

  1. 通過分割關閉的最後一行,則可以執行的是第一塊,然後評估最後一行;例如

    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) 
    

    這是有效的,但如果最後一條語句有多行,則會失敗。

  2. 如果代碼本身被修改以便結果存儲爲本地變量,則可以恢復此變量;例如

    code = """ 
    x = 4 
    y = 5 
    z = x + y 
    """ 
    
    globals = {} 
    locals = {} 
    exec(code, globals, locals) 
    assert locals['z'] == 9 
    

    再次,這工作,但只有當你能夠首先解析代碼塊在一般的方式,並適當地修改它。

有沒有簡單的方法來寫一般的exec_and_eval函數?

+0

我不認爲會有一個簡單的方法來做到這一點,雖然你也許能夠得到的地方使用https://docs.python.org/2/library/ast.html –

+0

你的輸入看起來像這樣的任何特定原因? – user2357112

+0

重複? http://stackoverflow.com/q/33908794/2301450 – vaultah

回答

5

基於使用ast模塊的@ kalzekdor的建議下,我想出了這個解決方案也就是上面張貼在精神@ vaultah的解決方案類似:

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, '<string>', mode='exec'), _globals, _locals) 
    return eval(compile(last, '<string>', mode='eval'), _globals, _locals) 

它還傳遞@ vaultah的組漂亮的測試 - 的案例:

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 
+0

很好的回答!你應該接受它,我絕對不會介意。 – vaultah

+0

我剛纔意識到這是唯一正確的答案,即使最後一個表達式是多行字符串時也是如此。我的沒有,所以請不要接受它。 – vaultah

+0

如果你堅持! - – jakevdp