您好,登錄后才能下訂單哦!
這篇文章主要講解了“Python初學者必備的文件讀寫方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python初學者必備的文件讀寫方法”吧!
?先,我們來看看下?這段代碼,并思考:這段代碼有沒有問題,如果有問題的話,要怎么改?
li = ['python',' is',' a',' cat'] with open('test.txt','w') as f: f.write(li)
現在公布答案,這段代碼會報錯:
TypeError Traceback (most recent call last) <ipython-input-6-57e0c2f5a453> in <module>() 1 with open('test.txt','w') as f: ----> 2 f.write(li) TypeError: write() argument must be str, not list
以上代碼的想法是將list列表內容寫?txt?件中,但是報錯 TypeError: write() argument must be str。
就是說,write()?法必須接受字符串(str)類型的參數。 Python中內置了str()?法,可以返回字符串版本的對象(Return a string version of object)。所以,上?的例?中,我們試試把 f.write(li) 改為 f.write(str(li)) ,先做?下字符串類型的轉化看看。代碼略。 這次沒有報錯了,但是打開?件就傻眼了吧,寫?的內容是“['python',' is',' a',' cat']”。怎么才能寫 成“python is a cat”呢? ?件寫操作還有?個writelines()?法,它接收的參數是由字符串組成的序列(sequence),實際寫?的效果是將全部字符串拼接在?起。字符串本身也是?種序列,所以當參數是字符串的時候,writelines()?法等價于write()。
# 以下3種寫法等價,都是寫?字符串“python is a cat” In [20]: with open('test.txt','w') as f: ...: f.writelines(['python',' is',' a',' cat']) ...: f.writelines('python is a cat') ...: f.write('python is a cat') # 以下2種寫法等價,都是寫?列表的字符串版本“['python',' is',' a',' cat']” In [21]: with open('test.txt','w') as f: ...: f.write(str(['python',' is',' a',' cat'])) ...: f.writelines(str(['python',' is',' a',' cat'])) # 作為反例,以下寫法都是錯誤的: In [22]: with open('test.txt','w') as f: ...: f.writelines([2018,'is','a','cat']) # 含?字符串 ...: f.write(['python','is','a','cat']) # ?字符串
由上可知,當多段分散的字符串存在于列表中的時候,要?writelines()?法,如果字符串是?整段,那直 接使?write()?法。如果要以整個列表的形式寫??件,就使?str()?法做下轉化。 這個問題還沒結束,如果列表中就是有元素不是字符串,?且要把全部元素取出來,怎么辦呢? 那就不能直接使?write()和writelines()了,需要先?for循環,把每個元素取出來,逐?str()處理。
In [37]: content=[1,' is',' everything'] In [38]: with open('test.txt','w') as f: ...: for i in content: ...: f.write(str(i))
需要注意的是,writelines()不會?動換?。如果要實現列表元素間的換?,?個辦法是在每個元素后?加 上換?符“\n”,如果不想改變元素,最好是?for循環,在寫?的時候加在末尾:for i in content: f.writelines(str(i)+“\n”) 引申?下,經過實驗,數字及元祖類型也可以作為write()的參數,不需轉化。但是dict字典類型不可以, 需要先?str()處理?下。字典類型?較特殊,最好是?json.dump()?法寫到?件。 總結?下,write()接收字符串參數,適?于?次性將全部內容寫??件;writelines()接收參數是由字符串 組成的序列,適?于將列表內容逐?寫??件。str()返回Python對象的字符串版本,使?需注意。
從?件中讀取內容有如下?法:
file.read([size]) 從?件讀取指定的字節數,如果未給定或為負則讀取所有。 file.readline([size]) 讀取整?,包括 "\n" 字符。 file.readlines([sizeint]) 讀取所有?并返回列表,若給定sizeint>0,則是設置?次讀多少字節,這是為了減輕讀取壓?。
簡??之,在不傳參數的情況下,read()對應write(),讀取全部內容;readlines()對應writelines(),讀取 全部內容(含換?符)并以列表形式返回,每個換?的內容作為列表的?個元素。
In [47]: with open('test.txt','r') as f: ...: print(f.read()) 1 is everything. python is a cat. this is the end. In [48]: with open('test.txt','r') as f: ...: print(f.readlines()) ['1 is everything.\n', 'python is a cat.\n', 'this is the end.']
但是,以上兩個?法有個缺點,當?件過?的時候,?次性讀取太多內容,會對內存造成極?壓?。讀操作還有?個readline()?法,可以逐?讀取。
In [49]: with open('test.txt','r') as f: ...: print(f.readline()) 1 is everything.
readline()讀取第??就返回,再次調?f.readline(),會讀取下??。 這么看來,readline()太笨拙了。那么,有什么辦法可以優雅地讀取?件內容呢? 回過頭來看readlines()?法,它返回的是?個列表。這不奇怪么,好端端的內容為啥要返回成列表呢? 再想想writelines()?法,把字符串列表寫??件正是這家伙?的事,readlines()?法恰恰是它的逆操作! ?writelines()?法要配合for循環,所以我們把readlines()與for循環結合,看看會怎樣。
In [61]: with open('test.txt','r') as f: ...: for line in f.readlines(): ...: print(line) 1 is everything. python is a cat. this is the end. # 讀取內容包含換?符,所以要strip()去掉換?符 In [62]: with open('test.txt','r') as f: ...: for line in f.readlines(): ...: print(line.strip()) 1 is everything. python is a cat. this is the end.
總結?下,readline()?較雞肋,不咋?;read()適合讀取內容較少的情況,或者是需要?次性處理全部內容的情況;?readlines()?的較多,?較靈活,因為for循環是?種迭代器,每次加載部分內容,既減少內 存壓?,??便逐?對數據處理。
前兩部分講了?件讀寫的??核??法,它們能夠起作?的前提就是,需要先打開?個?件對象,因為只有在?件操作符的基礎上才可以進?讀或者寫的操作。 打開?件?的是open()?法,所以我們再繼續講講這個?法。open() ?法?于打開?個?件,并返回?件對象,在對?件進?處理過程都需要使?到這個函數,如果該?件?法被打開,會拋出 OSError。
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
open()?法的參數?file(?件)是必需的,其它參數最常?的是mode(模式)和encoding(編碼)。 先說說encoding,?般來說,打開?件的編碼?式以操作系統的默認編碼為準,中?可能會出現亂碼,需要加encoding='utf-8'。
In [63]: with open('test.txt','r') as f: ...: for line in f.readlines(): ...: print(line.strip()) ----------------------- UnicodeDecodeError Traceback (most recent call last) <ipython-input-63-731a4f9cf707> in <module>() 1 with open('test.txt','r') as f: ----> 2 for line in f.readlines(): 3 print(line.strip()) UnicodeDecodeError: 'gbk' codec can't decode byte 0xa4 in positio n 26: illegal multibyte sequence In [65]: with open('test.txt','r',encoding='utf-8') as f: ...: for line in f.readlines(): ...: print(line.strip()) python is a cat.
再說mode,它指定?件打開的模式。
r': 以只讀模式打開(缺省模式)(必須保證?件存在)
'w':以只寫模式打開。若?件存在,則清空?件,然后重新創建;若不存在,則新建?件。
'a':以追加模式打開。若?件存在,則會追加到?件的末尾;若?件不存在,則新建?件。
常?的mode組合
'r'或'rt': 默認模式,?本讀模式
'w'或'wt': 以?本寫模式打開(打開前?件會被清空)
'rb': 以?進制讀模式打開 'ab': 以?進制追加模式打開
'wb': 以?進制寫模式打開(打開前?件會被清空)
'r+': 以?本讀寫模式打開,默認寫的指針開始指在?件開頭, 因此會覆寫?件
'w+': 以?本讀寫模式打開(打開前?件會被清空)
'a+': 以?本讀寫模式打開(寫只能寫在?件末尾)
'rb+': 以?進制讀寫模式打開
'wb+': 以?進制讀寫模式打開(打開前?件會被清空)
'ab+': 以?進制讀寫模式打開
初看起來,模式很多,但是,它們只是相互組合罷了。建議記住最基本的w、r、a,遇到特殊場景,再翻看?下就好了。
基礎部分講完了,下?是進階部分。知其然,更要知其所以然。
1、with語句是初學者必會常識
?先,要解釋?下為啥前?直接就?了with語句。with語句是讀寫?件時的優雅寫法,這已經默認是Python初學者必會的常識了。如果你還不會,先看看?和不?with語句的對?:
# 不?with語句的正確寫法 try: f = open('test.txt','w') f.writelines(['python',' is',' a',' cat']) finally: if f: f.close() # 使?with語句的正確寫法 with open('test.txt','w') as f: f.writelines(['python',' is',' a',' cat'])
因為?件對象會占?操作系統的資源,并且操作系統同?時間能打開的?件數量是有限的,所以open()?法之后?定要調?close()?法。另外,讀寫操作可能出現IO異常的情況,所以要加try...finally,保證?論如何,都會調?到close()?法。 這樣寫萬??失,但是實在繁瑣,?不??還可能漏寫或者寫錯。?with語句會保證調?close(),只需??代碼,簡直不要太優雅!所以,with語句是Python初學者必會技能。
2、什么是上下?管理器?
下?,重頭戲來了,什么是上下?管理器(context manager)?
上下?管理器是這樣?個對象:它定義程序運?時需要建?的上下?,處理程序的進?和退出,實現了上下?管理協議,即在對象中定義了 __enter__() 和 __exit__() ?法。 __enter__():進?運?時的上下?,返回運?時上下?相關的對象,with 語句中會將這個返回值綁定到?標對象。 __exit__(exception_type, exception_value, traceback):退出運?時的上下?,定義在塊執?(或終?)之后上下?管理器應該做什么。它可以處理異常、清理現場或者處理 with 塊中語句執?完成之后需要處理的動作。
注意 enter 和 exit 的前后有兩個下劃線,Python 中?帶了很多類似的?法,它們是很神秘?很強?的存在,江湖?常常稱其為“?魔法”。例如,迭代器協議就實現了__iter__?法。 在Python的內置類型中,很多類型都是?持上下?管理協議的,例如 file、thread.LockType、 threading.Lock 等等。上下?管理器?法獨?使?,它們要與 with 相結合,with 語句可以在代碼塊運?前進??個運?時上下?(執?__enter__?法),并在代碼塊結束后退出該上下?(執?__exit__?法)。 with 語句適?于對資源進?訪問的場合,確保不管使?過程中是否發?異常都會執?必要的“清理”操作,釋放資源,?如?件使?后?動關閉、線程中鎖的?動獲取和釋放等。
3、?定義上下?管理器
除了Python的內置類型,任何?都可以定義??的上下?管理器。下?是?個示例:
class OpenFile(object): def __init__(self,filename,mode): def open_file(name): ff = open(name, 'w') ff.write("enter now\n") try: yield ff except RuntimeError: pass ff.write("exit now") ff.close() with open_file('test.txt') as f: f.write('Hello World!\n')
最終寫??件的結果是:
enter now Hello World! exit now
上下?管理器必須同時提供 enter() 和 exit() ?法的定義,缺少任何?個都會導致 AttributeError。 上下?管理器在執?過程中可能會出現異常,exit() 的返回值會決定異常的處理?式:返回值等于 False,那么這個異常將被重新拋出到上層;返回值等于 True,那么這個異常就被忽略,繼續執?后?的代碼。exit() 有三個參數(exception_type, exception_value, traceback),即是異常的相關信息。
4、contextlib實現上下?管理器
上例中,?定義上下?管理器的寫法還是挺繁瑣的,?且只能?于類級別。為了更好地輔助上下?管理,Python 內置提供了 contextlib 模塊,進?可以很?便地實現函數級別的上下?管理器。 該模塊本質上是通過裝飾器(decorators)和?成器(generators)來實現上下?管理器,可以直接作?于函數/對象,?不?去關? enter() 和 exit() ?法的具體實現。 先把上?的例?改造?下,然后我們再對照著解釋:
from contextlib import contextmanager @contextmanager def open_file(name): ff = open(name, 'w') ff.write("enter now\n") try: yield ff except RuntimeError: pass ff.write("exit now") ff.close() with open_file('test.txt') as f: f.write('Hello World!\n')
contextmanager 是要使?的裝飾器,yield 關鍵字將普通的函數變成了?成器。yield 的返回值(ff)等于上例__enter__()的返回值,也就是 as 語句的值(f),? yield 前后的內容,分別是__enter__() 和__exit__() ?法?的內容。 使? contextlib,可以避免類定義、__enter__() 和 __exit__() ?法,但是需要我們捕捉可能的異常(例如,yield 只能返回?個值,否則會導致異常 RuntimeError),所以 try...except 語句不能忽略。
感謝各位的閱讀,以上就是“Python初學者必備的文件讀寫方法”的內容了,經過本文的學習后,相信大家對Python初學者必備的文件讀寫方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。