Python 開發模式¶
在 3.7 版本加入。
Python 開發模式引入了額外的執行時檢查,這些檢查的開銷太大,預設情況下無法啟用。如果程式碼正確,它不應比預設模式更詳細;只有在檢測到問題時才會發出新警告。
可以使用 -X dev
命令列選項或將 PYTHONDEVMODE
環境變數設定為 1
來啟用它。
另請參閱 Python 除錯構建。
Python 開發模式的影響¶
啟用 Python 開發模式類似於以下命令,但具有以下描述的額外效果
PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python -W default -X faulthandler
Python 開發模式的效果
新增
default
警告過濾器。將顯示以下警告通常,上述警告會被預設的 警告過濾器 過濾掉。
它的行為就好像使用了
-W default
命令列選項。使用
-W error
命令列選項或將PYTHONWARNINGS
環境變數設定為error
以將警告視為錯誤。在記憶體分配器上安裝除錯鉤子以檢查
緩衝區下溢
緩衝區溢位
記憶體分配器 API 違規
不安全的 GIL 使用
請參閱
PyMem_SetupDebugHooks()
C 函式。它的行為就好像
PYTHONMALLOC
環境變數設定為debug
。要啟用 Python 開發模式而不安裝記憶體分配器上的除錯鉤子,請將
PYTHONMALLOC
環境變數設定為default
。在 Python 啟動時呼叫
faulthandler.enable()
,為SIGSEGV
、SIGFPE
、SIGABRT
、SIGBUS
和SIGILL
訊號安裝處理程式,以便在崩潰時轉儲 Python 回溯。它的行為就好像使用了
-X faulthandler
命令列選項,或者將PYTHONFAULTHANDLER
環境變數設定為1
。啟用 asyncio 除錯模式。例如,
asyncio
會檢查未被等待的協程並記錄它們。它的行為就好像
PYTHONASYNCIODEBUG
環境變數設定為1
。檢查字串編碼和解碼操作的 *encoding* 和 *errors* 引數。例如:
open()
、str.encode()
和bytes.decode()
。預設情況下,為了獲得最佳效能,*errors* 引數只在第一次編碼/解碼錯誤時檢查,而 *encoding* 引數有時對於空字串會被忽略。
io.IOBase
解構函式會記錄close()
異常。
Python 開發模式預設不啟用 tracemalloc
模組,因為其開銷(對效能和記憶體)會太大。啟用 tracemalloc
模組可提供一些錯誤的額外資訊。例如,ResourceWarning
會記錄資源分配時的回溯,而緩衝區溢位錯誤會記錄記憶體塊分配時的回溯。
Python 開發模式不會阻止 -O
命令列選項移除 assert
語句,也不會阻止將 __debug__
設定為 False
。
Python 開發模式只能在 Python 啟動時啟用。其值可以從 sys.flags.dev_mode
中讀取。
3.8 版本中的變化: io.IOBase
解構函式現在會記錄 close()
異常。
3.9 版本中的變化: 現在會對字串編碼和解碼操作的 *encoding* 和 *errors* 引數進行檢查。
ResourceWarning 示例¶
一個計算命令列中指定文字檔案行數的指令碼示例
import sys
def main():
fp = open(sys.argv[1])
nlines = len(fp.readlines())
print(nlines)
# The file is closed implicitly
if __name__ == "__main__":
main()
指令碼沒有顯式關閉檔案。預設情況下,Python 不會發出任何警告。以下示例使用 README.txt,它有 269 行
$ python script.py README.txt
269
啟用 Python 開發模式會顯示 ResourceWarning
警告
$ python -X dev script.py README.txt
269
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>
main()
ResourceWarning: Enable tracemalloc to get the object allocation traceback
此外,啟用 tracemalloc
會顯示檔案開啟的行
$ python -X dev -X tracemalloc=5 script.py README.rst
269
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>
main()
Object allocated at (most recent call last):
File "script.py", lineno 10
main()
File "script.py", lineno 4
fp = open(sys.argv[1])
修復方法是顯式關閉檔案。以下示例使用上下文管理器
def main():
# Close the file explicitly when exiting the with block
with open(sys.argv[1]) as fp:
nlines = len(fp.readlines())
print(nlines)
不顯式關閉資源可能會導致資源開啟的時間比預期長得多;這可能會在退出 Python 時導致嚴重問題。在 CPython 中這很糟糕,但在 PyPy 中甚至更糟糕。顯式關閉資源會使應用程式更具確定性且更可靠。
錯誤檔案描述符示例¶
指令碼顯示自身的第一行
import os
def main():
fp = open(__file__)
firstline = fp.readline()
print(firstline.rstrip())
os.close(fp.fileno())
# The file is closed implicitly
main()
預設情況下,Python 不會發出任何警告
$ python script.py
import os
Python 開發模式會顯示一個 ResourceWarning
,並在檔案物件最終化時記錄“錯誤檔案描述符”錯誤
$ python -X dev script.py
import os
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>
main()
ResourceWarning: Enable tracemalloc to get the object allocation traceback
Exception ignored in: <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>
Traceback (most recent call last):
File "script.py", line 10, in <module>
main()
OSError: [Errno 9] Bad file descriptor
os.close(fp.fileno())
關閉檔案描述符。當檔案物件終結器再次嘗試關閉檔案描述符時,它會因 Bad file descriptor
錯誤而失敗。檔案描述符必須只關閉一次。在最壞的情況下,關閉兩次可能導致崩潰(請參閱 bpo-18748 以獲取示例)。
修復方法是移除 os.close(fp.fileno())
行,或者使用 closefd=False
開啟檔案。