1. 程式人生 > >Python檔案關閉機制詳解

Python檔案關閉機制詳解

如果不用“with”,那麼Python會在何時關閉檔案呢?答案是:視情況而定。

Python程式設計師最初學到的東西里有一點就是可以通過迭代法很容易地遍歷一個開啟檔案的全文:

Python
123 f=open('/etc/passwd')forline inf:print(line)

注意上面的程式碼具有可行性,因為我們的檔案物件“f”是一個迭代器。換句話說,“f“ 知道在一個迴圈或者任何其他的迭代上下文中做什麼,比如像列表解析。

我的Python課堂上的大多數學生都具有其他程式語言背景,在使用以前所熟悉的語言時,他們總是在完成檔案操作時被期望關閉檔案。因此,在我向他們介紹了Python檔案操作的內容不久後他們問起如何在Python中關閉檔案時,我一點都不驚訝。

最簡單的回答就是我們可以通過呼叫f.close()顯式地關閉檔案。一旦我們關閉了檔案,該檔案物件依然存在,但是我們無法再通過它來讀取檔案內容了,而且檔案物件返回的可列印內容也表明檔案已經被關閉。

Python
12345678910111213141516 >>>f=open('/etc/passwd')>>>f<openfile'/etc/passwd',mode'r'at0x10f023270>>>>f.read(5)'##n# 'f.close()>>>f<closed file'/etc/passwd',mode'r'at0x10f023270>f.read(5)----------------------------------------
-----------------------------------ValueErrorTraceback(most recent call last)<ipython-input-11-ef8add6ff846>in<module>()---->1f.read(5)ValueError:I/Ooperation on closed file

所以是這樣,我在用Python程式設計的時候,很少明確地對檔案呼叫 “close” 方法。此外,你也很可能不想或不必那樣做。

開啟檔案的優選最佳實踐方式是使用 “with” 語句,就像如下所示:

Python
123 withopen('/etc/passwd')asf:forline inf:print(line)

“with”語句對 “f” 檔案物件呼叫在Python中稱作“上下文管理器”的方法。也就是說,它指定 “f” 為指向 /etc/passwd 內容的新的檔案例項。在 “with” 開啟的程式碼塊內,檔案是開啟的,而且可以自由讀取。

然而,一旦Python程式碼從 “with” 負責的程式碼段退出,檔案會自動關閉。試圖在我們退出 “with”程式碼塊後從 f 中讀取內容會導致和上文一樣的 ValueError 異常。所以,通過使用 “with”,你避免了顯式地關閉檔案的操作。Python 會以一種不那麼有 Python 風格的方式在幕後神奇而靜靜地替你關閉檔案。

但是你不顯式地關閉檔案會怎樣?如果你有點懶,既不使用 “with” 程式碼塊也不呼叫f.close()怎麼辦?這時檔案會什麼時候關閉?何時應該關閉檔案?

我之所以問這個,是因為我教了這麼多年Python,確信努力教授“with”或上下文管理器的同時又教很多其它的話題超出了學生接受的範圍。在介紹性課程談及 “with” 時,我一般會告訴學生在他們職業生涯中遇到這個問題時,讓Python去關閉檔案就好,不論檔案物件的應用計數降為0還是Python退出時。

在我的Python檔案操作免費e-mail課程中,我並沒有在所有的解決方案中使用with,想看看如何。結果一些人質疑我,說不使用“with”會向人們展示一種糟糕的實踐方案並且會有資料未寫入磁碟的風險。

我收到了很多關於此話題的郵件,於是我問自己:如果我們沒有顯式地關閉檔案或者沒用“with”程式碼塊,那麼Python會何時關閉檔案?也就是說,如果我讓檔案自動關閉,那麼會發生什麼?

我總是假定當物件的引用計數降為0時,Python會關閉檔案,進而垃圾回收機制清理檔案物件。當我們讀檔案時很難證明或核實這一點,但寫入檔案時卻很容易。這是因為當寫入檔案時,內容並不會立即重新整理到磁碟(除非你向“open”方法的第三個可選引數傳入“False”),只有當檔案關閉時才會重新整理。

於是我決定做些實驗以便更好地理解Python到底能自動地為我做什麼。我的實驗包括開啟一個檔案、寫入資料、刪除引用和退出Python。我很好奇資料是什麼時候會被寫入,如果有的話。

我的實驗是這個樣子:

Python
12345678 f=open('/tmp/output','w')f.write('abcn')f.write('defn')# check contents of /tmp/output (1)del(f)# check contents of /tmp/output (2)# exit from Python# check contents of /tmp/output (3)

我在Mac平臺上用Python 2.7.9 做了第一個實驗,報告顯示在階段一檔案存在但是是空的,階段二和階段三中檔案包含所有的內容。這樣,在CPython 2.7中我最初的直覺似乎是正確的:當一個檔案物件被垃圾回收時,它的 __del__ (或者等價的)方法會重新整理並關閉檔案。而且在我的IPython程序中呼叫“lsof”命令顯示檔案確實在引用物件移除後被關閉了。

那 Python3 如何呢?我在Mac上 Python 3.4.2 環境下做了以上的實驗,得到了相同的結果。移除對檔案物件最後的引用後會導致檔案被重新整理並且被關閉。

這對於 Python 2.7 和 3.4 很好。但是在 PyPy 和 Jython下的替代實現會怎樣呢?或許情況會有些不同。

於是我在 PyPy 2.7.8 下做了相同的實驗。而這次,我得到了不同的結果!刪除檔案物件的引用後——也就是在階段2,並沒有導致檔案內容被刷入磁碟。我不得不假設這和垃圾回收機制的不同或其他在 PyPy 和 CPython中工作機制的不同有關係。但是如果你在 PyPy中執行程式,就絕不要指望僅僅因為檔案物件的引用結束,檔案就會被重新整理和關閉。命令 lsof 顯示直到Python程序退出時檔案才會被釋放。

為了好玩,我決定嘗試一下 Jython 2.7b3. 結果Jython 表現出了和PyPy一樣的行為。也就是說,從 Python 退出確實會確保快取中的資料寫入磁碟。

我重做了這些實驗,但是我把 “abcn”和 “defn”換成了 “abcn”*1000 和“defn”*1000.

在 Python 2.7 的環境下,“abcn” * 1000 語句執行後沒有任何東西寫入。但“defn” * 1000 語句執行後,檔案包含有4096個位元組——可能代表緩衝區的大小。呼叫 del(f) 刪除檔案物件的引用導致資料被刷入磁碟和檔案關閉,此時檔案中共有8000位元組的資料。所以忽略字串大小的話 Python 2.7 的行為表現基本相同。唯一不同的是如果超出了緩衝區的大小,那麼一些資料將在最後檔案關閉資料重新整理前寫入磁碟。

換做是Python 3的話,情況就有些不同了。f.write執行後沒有任何資料會寫入。但是檔案物件引用一旦結束,檔案就會重新整理並關閉。這可能是緩衝區很大的緣故。但毫無疑問,刪除檔案物件引用會使檔案重新整理並關閉。

至於 PyPy 和 Jython,對大檔案和小檔案的操作結果都一樣:檔案在 PyPy 或 Jython 程序結束的時候重新整理並關閉,而不是在檔案物件的引用結束的時候。

為了再次確認,我又使用 “with” 進行了實驗。在所有情況下,我們都能夠輕鬆的預測檔案是何時被重新整理和關閉的——就是當退出程式碼段,並且上下文管理器在後臺呼叫合適方法的時候。

換句話說,如果你不使用“with”,那麼至少在非常簡單的情形下,你的資料不一定有丟失的危險。然而你還是不能確定資料到底是在檔案物件引用結束還是程式退出的時候被儲存的。如果你假定因為對檔案唯一的引用是一個本地變數所以檔案在函式返回時會關閉,那麼事實一定會讓你感到吃驚。如果你有多個程序或執行緒同時對一個檔案進行寫操作,那麼你真的要非常小心了。

或許這個行為可以更好地定義不就可以在不同的平臺上表現得基本一致了嗎?也許我們甚至可以看看Python規範的開始,而不是指著CPython說“Yeah,不管版本如何總是對的”。

我依然覺得“with”和上下文管理器很棒。而且我想對於Python新手,理解“with”的工作原理很難。但我還是不得不提醒新手開發者注意:如果他們決定使用Python的其他可選版本,那麼會出現很多不同於CPython的古怪情況而且如果他們不夠小心,甚至會深受其害。

如果你喜歡這篇文章內容,那麼不妨看看我的關於Python檔案操作的 free e-mail course 或者我的電子書,“Practice Makes Python”,其中包含50個經過實際測試的Python程式設計練習。

相關推薦

Python檔案關閉機制

如果不用“with”,那麼Python會在何時關閉檔案呢?答案是:視情況而定。 Python程式設計師最初學到的東西里有一點就是可以通過迭代法很容易地遍歷一個開啟檔案的全文: Python f = open('/etc/

Android的so檔案載入機制

今日科技快訊 10月30日,小米集團跌超4%,再創上市以來新低,市值下破2600億港元關口。此前,財政部發布的《2018年會計資訊質量檢查公告》顯示,在2017年度會計執法檢查中發現,部分企業跨境轉移利潤、逃避繳納稅收等問題比較突出。在被點名的網際網路企業中,就包括

Python垃圾回收機制

func 缺陷 詳解 調用函數 lec objects string 入參 collect 一.垃圾回收機制 Python中的垃圾回收是以引用計數為主,分代收集為輔。引用計數的缺陷是循環引用的問題。在Python中,如果一個對象的引用數為0,Python虛擬機就會回收這個對

Python相對匯入機制

本文是對 http://stackoverflow.com/questions/14132789/python-relative-imports-for-the-billionth-time#answer-14132912 這個 SO 答案的翻譯。本人的翻譯一向只追求含義準確而不追求

【轉】kafka-檔案儲存機制

文章轉自“美團技術部落格”:https://tech.meituan.com/ Kafka是什麼 Kafka是最初由Linkedin公司開發,是一個分散式、分割槽的、多副本的、多訂閱者,基於zookeeper協調的分散式日誌系統(也可以當做MQ系統),常見可以用於web

python檔案開啟方式——a、a+、r+、w+區別

轉載於 http://blog.csdn.net/ztf312/ 第一步 排除檔案開啟方式錯誤:r只讀,r+讀寫,不建立w新建只寫,w+新建讀寫,二者都會將檔案內容清零(以w方式開啟,不能讀出。w+可讀寫)w+與r+區別:r+:可讀可寫,若檔案不存在,報錯;w+: 可讀可寫,

Pythonpython檔案開啟方式——a、a+、r+、w+區別

第一步 排除檔案開啟方式錯誤: r只讀,r+讀寫,不建立 w新建只寫,w+新建讀寫,二者都會將檔案內容清零 (以w方式開啟,不能讀出。w+可讀寫) w+與r+區別: r+:可讀可寫,若檔案不存在,報錯;w+: 可讀可寫,若檔案不存在,建立 r+與a+區別: fd

python和mysql互動---- (pandas)讀csv檔案,executemny批量寫入db中

主要用到pandas從csv檔案中抓資料,pandas抓出的資料是dataframe格式的,而且有的可能是Nan,抓出df格式的資料需要再處理,才能批處理的寫入資料庫中,executemany批出的格式不能是df,這裡處理成list import pymysql import codec

Python反射機制

一、前言 def f1():    print('f1') def f2():    print('f2') def f3():    print('f3') def f4():    print('f4') a = 1

Python import機制

一 module通常模組為一個檔案,直接使用import來匯入就好了。可以作為module的檔案型別有".py"、".pyo"、".pyc"、".pyd"、".so"、".dll"。 二 package通常包總是一個目錄,可以使用import匯入包,或者from +

Python內建函式open()&檔案屬性方法

Python檔案物件開啟模式及其屬性方法詳解1、檔案系統和檔案檔案系統:檔案系統是OS用於明確磁碟或分割槽上的檔案的方法和資料結構,即在磁碟上組織檔案的方法檔案:儲存在某種長期儲存裝置或臨時儲存裝置中的一段資料流,並且受計算機檔案系統管理。概括來講,檔案是計算機中有OS管理的

Python基礎:opencv讀取視訊檔案的方法

前言 今天為大家分享一個Python利用opencv這個第三方庫來實現讀取視訊檔案的例項,你可以對視訊進行更多的操作,也更好的使

Python __init__.py 作用

引用文件 site linu 塊對象 and 語句 inux python url __init__.py 文件的作用是將文件夾變為一個Python模塊,Python 中的每個模塊的包中,都有__init__.py 文件。 通常__init__.py 文件為空,但是我們還可

四、python之函數

list global pan line ice see war -s span 一、函數 1.說白了就是把一組代碼合到一起,可以實現某種功能,需要再用到這種功能的話,直接調用這個函數就行2.函數、方法是一回事3.定義一個函數的格式是:def+函數名+()4.函數必須調用了

[轉載]Python logging模塊

.html key 文件名 屏幕 輸出 mov say line log 原文地址: http://blog.csdn.net/zyz511919766/article/details/25136485 簡單將日誌打印到屏幕: [python] view plain c

Python itertools模塊

abcd avi pool argument osi 復制 lists 代碼 fetch 這貨很強大, 必須掌握 文檔 鏈接 http://docs.python.org/2/library/itertools.html pymotw 鏈接 http://pymotw.co

Java反射機制

java 反射 反射機制 工廠模式 1反射機制是什麽反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。在面向對象的世界裏,萬事萬物皆對象.在ja

Java垃圾回收(GC)機制

nbsp 引用計數 維護 png 對象 最新 新的 com 前沿 垃圾回收算法有兩種,根據不同的虛擬機策略不同 1、引用計數法 2、可達性分析法 由於我們平常使用的hotspot虛擬機用的是第二種。 那哪些是可達的呢? 這個算法的基本思想是通過一系列稱為“GC Roots”

Python匿名函數

abcd highlight pack ces iss 無需 最好 pri 必須 轉載自傑瑞的專欄 lambda這個名稱來自於LISP,而LISP則是從lambda calculus(一種符號邏輯形式)取這個名稱的。在Python中, lambda作為一個關鍵字,作為引入表

Java的內存回收機制

out 結果 int destroy pan 得出 ida public toc http://blog.csdn.net/mengern/article/details/38150431 Java中提供了垃圾強制回收機制的方法System.gc(),但是系統並不保證會立即