英文:https://arpitbhayani.me/blogs/constant-folding-python
作者:arprit
譯者:豌豆花下貓(“Python貓”公眾號作者)
宣告:本翻譯是出于交流學習的目的,基于 CC BY-NC-SA 4.0 授權協議,為便于閱讀,內容略有改動,
每種編程語言為了表現出色,并且實作卓越的性能,都需要大量編譯器級的優化,
一種著名的優化技術是“常量折疊”(Constant Folding):在編譯期間,編譯器會設法識別出常量運算式,對其進行求值,然后用求值的結果來替換運算式,從而使得運行時更精簡,
在本文中,我們深入探討了什么是常量折疊,了解了它在 Python 世界中的適用范圍,最后解讀了 Python 的源代碼(即 CPython),并分析出 Python 是如何優雅地實作它,
常量折疊
所謂常量折疊,指的是在編譯時就查找并計算常量運算式,而不是在運行時再對其進行計算,從而會使運行時更加精簡和快速,
>>> day_sec = 24 * 60 * 60
當編譯器遇到一個常量運算式時,如上所述,它將對運算式求值,并作替換,
通常而言,運算式會被“抽象語法樹”( Abstract Syntax Tree,簡寫為 AST)中的計算值所替換,但是這完全取決于語言的實作,
因此,上述運算式可以等效地被執行為:
>>> day_sec = 86400
Python 中的常量折疊
在 Python 中,我們可以使用反匯編模塊(Disassembler)獲取 CPython 位元組碼,從而更好地了解代碼執行的程序,
當使用dis模塊反匯編上述常量運算式時,我們會得到以下位元組碼:
>>> import dis
>>> dis.dis("day_sec = 24 * 60 * 60")
0 LOAD_CONST 0 (86400)
2 STORE_NAME 0 (day_sec)
4 LOAD_CONST 1 (None)
6 RETURN_VALUE
從位元組碼中可以看出,它只有一個LOAD_CONST ,以及一個已經計算好的值86400,
這表明 CPython 解釋器在決議和構建抽象語法樹期間,會折疊常量運算式 24 * 60 * 60,并將其替換為計算值 86400,
常量折疊的適應范圍
Python 會嘗試折疊每一個常量運算式,但在某些情況下,即使該運算式是常量,但是 Python 并不會對其進行折疊,
例如,Python 不會折疊x = 4 ** 64,但會折疊 x = 2 ** 64,

除了算術運算式,Python 還會折疊涉及字串和元組的運算式,其中,長度不超過 4096 的字串常量運算式會被折疊,
>>> a = "-" * 4096 # folded
>>> a = "-" * 4097 # not folded
>>> a = "--" * 4096 # not folded
常量折疊的內部細節
現在,我們將重點轉移到內部的實作細節,即關注 CPython 在哪里以及如何實作常量折疊,
所有的 AST 優化(包括常量折疊)都可以在 ast_opt.c 檔案中找到,基本的開始函式是 astfold_expr,它會折疊 Python 原始碼中包含的所有運算式,
這個函式以遞回方式遍歷 AST,并試著折疊每個常量運算式,如下面的代碼片段所示:

astfold_expr 在折疊某個運算式之前,會嘗試折疊其子運算式(操作物件),然后將折疊操作代理給特定的運算式折疊函式,
特定操作的折疊函式對運算式求值,并回傳計算后的常數,然后將其放入 AST 中,
例如,每當 astfold_expr 遇到二值運算時,它便呼叫 fold_binop,遞回地計算兩個子操作物件(運算式) ,
fold_binop 函式回傳計算后的常量值,如下面的代碼片段所示:

fold_binop 函式通過檢查當前運算子的種類,然后呼叫其相應的處理函式來折疊二值運算,例如,如果當前的操作是加法運算,為了計算最終值,它會對其左側和右側運算元呼叫 PyNumber_Add,
怎樣優雅?
為了有效地折疊某些模式或型別的常量運算式,CPython 不會寫特殊的邏輯,而是呼叫相同的通用代碼,例如,在折疊時,它會呼叫通用的 PyNumber_Add 函式,跟執行常規的加法操作一樣,
因此,CPython 通過確保其通用代碼/計算程序可以處理常量運算式的求值,從而消除了撰寫特殊函式來處理常量折疊的需要,
參考材料
- 常量折疊 (https://en.wikipedia.org/wiki/Constant_folding)
- CPython優化(https://stummjr.org/post/cpython-optimizations/)
- Python dis模塊與常量折疊(https://yasoob.me/2019/02/26/python-dis-module-and-constant-folding/)
- CPython實作常量折疊的簡單方法(https://utcc.utoronto.ca/~cks/space/blog/python/CPythonConstantFolding)
- ? AST的常量折疊優化程序(https://bugs.python.org/issue1346238)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/259407.html
標籤:AI
上一篇:為何你進不了大廠?
