使用Python時多少有人走過的坑!避險!

2020-09-29 21:00:41

毫無疑問, print 函數是我們日常最常用的函數,無論是格式化輸出還是列印中間變數進行偵錯,幾乎沒有 print 接不了的活兒。

但是上一次阿醬就差點被 print 給坑了。

坑從何來

最初是想要為自己的一個命令列小工具增加一個進度顯示功能,於是用了 threading 模組來實現多執行緒,一個執行緒用於執行實際的邏輯,另一個執行緒用於列印當前進度。

點選並拖拽以移動

根據我們

多年 使用命令列的經驗,一般列印進度都是在行內列印,而Python的 print

則會預設在結尾列印一個換行符,這就十分不美了。

不過好在, print 也提供了介面來改變列印的末尾字元,通過指定 printend 引數,即可改變 print 的列印結果。

所以我就哼哧哼哧地開幹了,把列印進度的 print("#") 呼叫改為 print("#", end="")

類似這樣:

點選並拖拽以移動

哪成想,這麼一改卻出了大問題:進度沒法實時列印了。

點選並拖拽以移動

也就是說,本來應該在程式執行期間,挨個列印出來的 # 號不再是聽話的、可愛的 # 號了,而是在整個程式執行完成之後一次性輸出到控制檯中。

它長大了, 也變醜了

點選並拖拽以移動

那我要你有何用?

點選並拖拽以移動

啥問題呢?

一開始阿醬以為是多執行緒出了問題,傻乎乎地到處找資料來「佐證」自己的各種猜測——事後想來實在太傻了,以至於現在說起還是會哈哈哈

點選並拖拽以移動

這件事給我們的教訓就是: 千萬不要自以為是,而應踏踏實實地解決問題,虛心對待每個細節 。

實際上,之所以我們看不到實時的輸出,就是因為我們改變了 print 的結尾字元。

為了儘量減少I/O操作,Python存在一個這樣的機制:儘量將輸出字元快取起來,當遇到字串結束、換行符或強制重新整理緩衝區時,才會一次性將緩衝區的內容輸出到相應的流中。

——而我們改掉的地方,就是把 print 預設的換行符去掉了,所以原本每一個 print 都會觸發一次緩衝區重新整理,變成了現在一直觸發不了緩衝區重新整理,直到程式結束觸發一次。

好嘛,知道了啥問題,我們又吭哧吭哧找資料,聽說 sys.stdout.flush 可以強制觸發標準輸出緩衝區的重新整理,於是在 print 後面,緊跟著又加上了 sys.stdout.flush()

誒?還真好了?

點選並拖拽以移動

這些可都是知識點,快記下來記下來,要考的

點選並拖拽以移動

讓我們檢視 print 的官方檔案,其原型為:

點選並拖拽以移動

根據其下的描述,Python中 print 的輸出是否進行緩衝,取決於兩個引數: fileflush

file 的型別有的需要緩衝,比如 sys.stdout ;而有的則不需要緩衝,比如 sys.stderr

對於 flush 引數,當其值為 False (預設)時,是否緩衝依賴 file ;而當其值為 True 時,則會強制重新整理緩衝區。

我們把範例呼叫中的 print 呼叫修改一下:

點選並拖拽以移動
點選並拖拽以移動

同樣可以實現進度的實時列印。

此外,還有一種方法,在呼叫程式時增加一個 -u 選項,也可以實現緩衝區的實時重新整理:

點選並拖拽以移動
點選並拖拽以移動

當然這種方法就不太推薦了,畢竟不能對程式的使用者作任何預設。

總結

本文是阿醬的一次踩坑實錄,記錄了Python中一個很少有人會遇到的奇葩問題。

總的來說,要想成為一個真正的Python程式設計師,只是單純掌握基本語法和一些奇技淫巧是遠遠不夠的,還是需要對Python本身有一定的瞭解。

畢竟,劍客如果不熟悉自己的劍,又該如何行走江湖呢?

相關免費學習推薦:

以上就是使用Python時多少有人走過的坑!避險!的詳細內容,更多請關注TW511.COM其它相關文章!