2016-11-16 73 views
12

我正在嘗試編寫Python表達式評估可視化器,它將顯示如何逐步評估Python表達式(用於教育目的)。 Philip Guo的Python Tutor非常棒,但它逐行評估Python程序,並且我發現學生有時不明白如何評估單行表達式sorted([4, 2, 3, 1] + [5, 6])[1] == 2,並且想要將此過程可視化。 (似乎沒有人去做,但 - 至少我什麼也沒發現。)理想的解決方案將創建的字符串這樣的順序:逐步跟蹤Python表達式評估

sorted([4, 2, 3, 1] + [5, 6])[1] == 2 
sorted(>> [4, 2, 3, 1] + [5, 6] <<)[1] == 2 
>> sorted([4, 2, 3, 1, 5, 6]) << [1] == 2 
>> [1 2 3 4 5 6][1] << == 2 
>> 2 == 2 << 
True 

這裏>><<被用來強調的是表達的一部分評估當前步驟,然後用其值替換。 (也許,我會稍後再嘗試這個序列轉換爲某種動畫。)

我目前的策略是使用ast.parse()解析字符串轉換成AST,然後發現,將首先評估一個節點,eval(compile(node, '', 'eval'))對其進行評估(我絕對不希望重新實現整個Python :)),將評估結果轉換爲AST節點(使用repr,然後使用ast.parse()?),並將結果節點替換爲當前節點,然後使用codegen.to_source生成修改後的代碼字符串從(修改)AST並繼續相同的過程,直到我在樹中只有一個文字。

我的問題是:我如何找到一個將首先評估的節點?似乎我可以深入遍歷樹的子類ast.NodeVisitor,但我不確定如何檢測到我到達了所需的節點,並且如何在它之後停止遍歷?


編輯。

有可能我的初始方法與樹的轉換不可行。實際上,評估Python表達式的基本步驟並不是必須的,它必須將某個子表達式替換爲更簡單的子表達式(如在算術中)。例如,列表解析提供了一個非常複雜的行爲,不能用來代替這個東西,然後遞歸地重複。所以我重申一個問題。我需要一些編程方法來展示如何逐步評估Python表達式。例如,@ jasonharper提到的MacroPy的tracing功能在此階段是可接受的解決方案。不幸的是,MacroPy似乎被拋棄了,並且不適用於Python 3.是否有任何想法如何在不移植完整MacroPy的情況下類似於Python 3中的跟蹤行爲?


EDIT2。

就在我獲得這個獎勵後,我發現similar questiondebugger與非常接近的功能。然而,由於這個問題沒有最終答案,而且我也不需要完整的調試器,所以我仍然在尋找一個可以在Jupyter環境中使用的答案。

回答

6

表達步進在Thonny IDE實現。

它使用AST儀器,其中每個(子)表達e轉換爲after(before(<location info>), e)。函數beforeafter是虛擬函數,用於在Python的跟蹤系統中導致額外的調用 -events。這些額外的電話會在(子)表達評估即將開始或剛結束時通知。 (添加了類似的虛擬函數來檢測每個語句的開始和結束。)

AST儀器和這些新事件的解釋在thonny.backend.FancyTracer中完成。

Python的AST節點包含相應文本範圍的起始位置,但它們有時不正確。完成位置完全丟失。 thonny.ast_utils.mark_text_ranges試圖照顧這一點(但目前的解決方案不完整)。

如果有人從Thonny中提取相關的功能到一個更一般的包,那將會很好。也許甚至有兩個軟件包 - 一個用於計算Python AST的位置信息,另一個用於詳細跟蹤Python代碼。如果有人帶頭,我願意爲此提供幫助。

1

添加這兩個列表肯定不是該代碼中要評估的第一個節點;我相信,其實早9個評估 - sorted4231[4,2,3,1]56[5,6]。您不僅需要確定執行哪些訂單評估,還必須確定哪些評估值得展示。

我認爲一個更好的方法是修改AST節點,以便它們發出它們之前/之後的狀態作爲執行的副作用。你不會關心他們的命令,你只需執行一次整個表達式。並且已經有一個名爲macropy的軟件包,它具有跟蹤功能,可以完成此操作。它的輸出並不完全符合你的要求,但它可能會被修改爲更接近的匹配。

+0

Hm-m,'macropy''s [tracing](https://github.com/lihaoyi/macropy#tracing)看起來非常接近,很有前途,謝謝。我必須深入研究它。 –

+0

唉,'macropy'不適用於Python 3 :( –

2

爲什麼不使用dis模塊?

由於CPython將Python編譯爲字節碼並運行它,查看字節碼可以讓您最清楚實際發生的情況。

In [1]: import dis 

In [2]: dis.dis('sorted([4, 2, 3, 1] + [5, 6])[1] == 2') 
    1   0 LOAD_NAME    0 (sorted) 
       3 LOAD_CONST    0 (4) 
       6 LOAD_CONST    1 (2) 
       9 LOAD_CONST    2 (3) 
      12 LOAD_CONST    3 (1) 
      15 BUILD_LIST    4 
      18 LOAD_CONST    4 (5) 
      21 LOAD_CONST    5 (6) 
      24 BUILD_LIST    2 
      27 BINARY_ADD 
      28 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      31 LOAD_CONST    3 (1) 
      34 BINARY_SUBSCR 
      35 LOAD_CONST    1 (2) 
      38 COMPARE_OP    2 (==) 
      41 RETURN_VALUE 

編輯:另一種方法可以是,以顯示步驟中的一個接一個在IPython的:

In [1]: [4, 2, 3, 1] 
Out[1]: [4, 2, 3, 1] 

In [2]: [4, 2, 3, 1] + [5, 6] 
Out[2]: [4, 2, 3, 1, 5, 6] 

In [3]: sorted([4, 2, 3, 1, 5, 6]) 
Out[3]: [1, 2, 3, 4, 5, 6] 

In [4]: [1, 2, 3, 4, 5, 6][1] 
Out[4]: 2 

In [5]: 2 == 2 
Out[5]: True 
+0

從技術上講,這是正確的。但是,我的問題的目的是創建一個工具,它可以幫助我在Python初學階段教授學生,熟悉軟件編程的基本概念,這不是計算機科學的學生,Python是他們的工具,而不是科學興趣的對象,因此,向他們展示字節碼是問題的答案是絕對不可能的。在這裏?*。也許,有可能以某種方式解析字節碼,以可訪問的方式重建過程,但它看起來並不簡單。 –

+0

@ IlyaV.Schurov由於您正在教學生的「第一步」 Python,爲什麼要「封閉」呢?而且由於我是一個使用Python作爲工具的培訓機械工程師,我認爲我可以說非計算機科學家有可能知道Pyth在作品上。 :-) –

+0

當然有可能。我既不是計算機科學家:)但我認爲我們在開始時並不需要它。這有點像「在Facebook上登錄之前,你必須學習x86架構,彙編,C,TCP/IP協議,HTTP協議,HTML,CSS和Javascript,然後發佈你的照片。糟糕,停下來,我們忘了JPEG「。Anywhay,感謝這個想法,很好。 –