Python基础(十)--文件相关
目錄
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Python基礎(chǔ)(十)--文件相關(guān)
1 讀寫文件
1.1 獲取文件對象
1.2 文件讀取
1.3 文件寫入
1.4 文件定位
2 文件與路徑的操作
2.1 os模塊
2.2 os.path模塊
2.3 shutil模塊
2.4 glob模塊
3 序列化
3.1 csv
3.2 json
3.3 pickle
4 上下文管理器
4.1 自定義上下文管理器
4.2?@contextmanager裝飾器
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Python基礎(chǔ)(十)--文件相關(guān)
1 讀寫文件
1.1 獲取文件對象
在操作系統(tǒng)中,一個(gè)text文檔,一張圖片,一首音樂,這些都是文件。文件會以其固有的格式保存在硬盤中。文件可以分為兩種類型:①文本文件:文本文件由若干可識別的字符組成,并且不能包含非文本字符之外的內(nèi)容(圖片等),如,.txt,.bat都是文本文件,而.doc,.pdf則不是文本文件②二進(jìn)制文件:由可識別的字符組成,如果我們用文本編輯器打開二進(jìn)制文件,往往看到的都是一堆亂碼。
底層的角度來說,一切都是二進(jìn)制格式的,文本文件,也是二進(jìn)制文件的一種,只是其內(nèi)容,是我們能夠識別的字符而已。
在Python中,可以通過open函數(shù)返回文件對象。文件對象是一個(gè)泛指,可以表示文件,也可以表示文件夾(路徑)。格式為:open(file, mode='r') file指定文件的路徑(相對路徑或絕對路徑),mode指定打開文件的模式,如下表。當(dāng)讀入文件或者寫入文件時(shí),會涉及到文件指針。文件指針指向的就是下一次要讀取或?qū)懭氲淖址?#xff08;或字節(jié))位置,隨著讀取或?qū)懭氲倪M(jìn)行,文件指針也會隨之而移動。
| 模式 | 說明 |
| r(1) | 讀模式(默認(rèn)模式),用來讀取文件內(nèi)容。文件指針在文件的開頭。文件需要事先存在,否則會產(chǎn)生異常。 |
| w(1) | 寫模式,用來向文件寫入數(shù)據(jù)。文件指針在文件的開頭。如果文件存在,則覆蓋文件,否則會創(chuàng)建文件。 |
| a(1) | 追加模式,用來向文件追加數(shù)據(jù)。文件指針在文件的末尾。如果文件存在,不會覆蓋文件(追加寫入),否則會創(chuàng)建文件。 |
| x(1) | 寫模式,用來向文件寫入數(shù)據(jù)。文件指針在文件的開頭。如果文件不存在,創(chuàng)建文件,否則產(chǎn)生錯(cuò)誤。 |
| t(2) | 文本(字符串)模式(默認(rèn)模式),以文本形式操作文件。 |
| b(2) | 二進(jìn)制(字節(jié))模式,以二進(jìn)制形式操作文件。 |
| U(3) | 通用換行符模式(已不建議使用)。在該模式下,\n,\r\n或\r都會解析為換行符。不能與w、a、x或+模式同時(shí)使用(僅限于讀取文件時(shí)使用)。 |
| +(3) | 讀取或?qū)懭搿?/p> |
上表的(1)(2)(3)模式中,不同組的模式可同時(shí)使用(除了與U不兼容的模式),例如rt,wb+等。同一組的模式同時(shí)使用,如rw,tb等。
當(dāng)文件不再使用時(shí),我們需要對文件進(jìn)行關(guān)閉,從而斷開與外部文件的連接。斷開連接可以調(diào)用文件對象的close方法。
# open函數(shù),參數(shù)1:文件路徑,參數(shù)2:操作文件的模式,返回文件對象 # 以r(讀取)模式操作文件時(shí),文件必須存在,否則會產(chǎn)生FileNotFoundError fr = open("E:/test/test.txt","r") # 以w(寫入)或a(追加)模式操作文件時(shí),文件不存在,不報(bào)錯(cuò)而是創(chuàng)建文件 fw = open("E:/test/test1.txt","w") fa = open("E:/test/test2.txt","a") # 以x(寫入)模式操作文件時(shí),文件必須存在,否則會產(chǎn)生FileNotFoundError fx = open("E:/test/test3.txt","w") # 訪問文件結(jié)束后,需要斷開與文件的連接,直接調(diào)用close并不好,可能在close方法前產(chǎn)生異常 # finally方式關(guān)閉文件 try:f = open("E:/test/test.txt", "r") finally:f.close() # with處打開文件,可以保證在with結(jié)束后一定能夠有效的關(guān)閉,無序顯示調(diào)用close方法 # with中可以使用as來保存文件對象(獲得文件兌現(xiàn)高的引用) with open("E:/test/test.txt") as f:pass1.2 文件讀取
讀取文件的幾種方式如下:
| 方法 | 描述 |
| read(size=-1) | 讀取并返回文件內(nèi)容。size指定讀取的大小。如果是文本模式,以字符為單位,如果是二進(jìn)制模式,以字節(jié)為單位。如果size省略,或者為負(fù)數(shù),則返回文件的全部內(nèi)容。如果文件已經(jīng)沒有內(nèi)容可讀取,返回空串(""或b"") |
| readlline() | 返回文件的一行,保留末尾的換行符。如果沒有內(nèi)容可以讀取,返回空串(""或b"")。 |
| readllines() | 返回一個(gè)列表,列表中的每個(gè)元素為文件的一行內(nèi)容,每行保留末尾的換行符。 |
文件對象也是迭代器:如果文件過大,這會占據(jù)大量的內(nèi)容空間。此時(shí)readlines不是一個(gè)好的選擇。對于文件對象,其本身也是一個(gè)迭代器類型,我們可以使用for循環(huán)的方式對文件對象進(jìn)行迭代,從而節(jié)省內(nèi)存。
# 文件讀寫操作 with open("E:/test/test.txt","rt") as f:# t模式以字符(文本)形式操作文件,b模式以字節(jié)(二進(jìn)制)形式操作文件# read讀取文件的數(shù)據(jù),參數(shù)指定讀取的單位,如果參數(shù)缺失,或者為負(fù)值表示讀取所有# print(f.read(1))# print(f.read())pass # 如果使用了t模式,要求操作文件的編碼方式與目標(biāo)文件的編碼方式一致 # 如果沒有顯示指定編碼方式,則使用平臺的編碼方式,可以使用encoding指定操作文件的編碼方式 with open("E:/test/test.txt","rt",encoding="UTF-8") as f:print(f.read())# 讀取文件的一行while True:line = f.readline()if line:print(line,end=" ")else:break# 返回一個(gè)列表,列表中的元素為每一行的內(nèi)容,保留換行符# lines = f.readlines()# for line in lines:# print(line,end=" ") # 文件是迭代器類類型,每個(gè)元素就是文件的一行 from collections.abc import Iterator with open("E:/test/test.txt","rt",encoding="UTF-8") as f:print(isinstance(f,Iterator))for line in f:print(line,end="")1.3 文件寫入
向文件寫入的幾種方式如下:
| 方法 | 描述 |
| write(content) | 將參數(shù)寫入到文件中,返回寫入的長度。如果是文本模式,以字符為單位,如果是二進(jìn)制模式,以字節(jié)為單位 |
| writelines(lines) | 參數(shù)lines為列表類型,將列表中所有元素寫入文件中 |
1.4 文件定位
通過文件對象的tell()和seek()方法可以獲取或設(shè)置文件指針的位置
tell():返回文件指針的位置,即下一個(gè)要讀取或?qū)懭氲淖址?#xff08;字節(jié))位置。以字節(jié)為單位。
seek(offset, whence):?改變文件的指針。offset指定新的索引位置偏移量。whence指定偏移量的參照位置:0:從文件頭計(jì)算;1:從當(dāng)前位置計(jì)算;2:從文件末尾計(jì)算
在文本模式下,如果whence的值不為0,則僅當(dāng)offset的值為0時(shí)才是有效的。
# 文件定位 with open("E:/test/a.txt","rt",encoding="UTF-8") as f:# 返回當(dāng)前文件指針的位置,以字節(jié)為單位print(f.tell())f.read(2)print(f.tell())# 改變文件指針的位置,參數(shù)1:偏移量,參數(shù)2:參照物# 在t模式下,如果第二個(gè)參數(shù)不為0,則只有第一個(gè)參數(shù)為0才支持,b模式無此限制f.seek(3,0)print(f.tell())2 文件與路徑的操作
2.1 os模塊
os模塊提供了很多操作目錄與文件的功能,常用方法如下:
| 方法名 | 描述 |
| mkdir(path) | 創(chuàng)建path指定的目錄。如果path所在的父目錄不存在,或者path目錄已經(jīng)存在,都會產(chǎn)生異常 |
| makedirs(path,exist_ok=False) | 創(chuàng)建path指定的目錄。如果path所在的父目錄不存在,則會連同父目錄一同創(chuàng)建。如果path目錄已經(jīng)存在,當(dāng)exist_ok值為False,會產(chǎn)生異常,如果exist_ok值為True,則不會產(chǎn)生異常(默認(rèn)值為False) |
| rmdir(path) | 刪除path指定的空目錄,但不會刪除父目錄。如果path目錄不存在,或者該目錄不為空,將會產(chǎn)生異常 |
| removedirs(path) | 刪除path指定的空目錄。如果父目錄也為空,則會連同父目錄一同刪除(一直到根目錄為止)。如果path不存在,或者該目錄不為空,將會產(chǎn)生異常 |
| remove(path) | 刪除path指定的文件。如果path不是一個(gè)文件,或者文件不存在,將會產(chǎn)生異常 |
| getcwd() | 返回當(dāng)前的工作目錄,即以腳本運(yùn)行文件所在的目錄 |
| chdir(path) | 改變當(dāng)前的工作目錄,工作目錄由path指定 |
| rename(src,dst) | 重命名一個(gè)文件或目錄。src指定源文件的路徑,dst指定重命名后的文件路徑。src與dest要求為同一目錄 |
| renames(old,new) | 與rename相似,但是old與new指定的目錄可以不同(此時(shí)類似于移動文件)。在方法執(zhí)行時(shí),會刪除old路徑中左側(cè)所有的非空目錄,并根據(jù)需要,創(chuàng)建new路徑中不存在的目錄。在Windows系統(tǒng),old與new必須在同一盤符中 |
| listdir(path) | 獲取path指定目錄下所有的文件與子目錄名(包括隱藏文件),以列表形式返回。列表元素的順序是沒有任何保證的。如果path為空,則默認(rèn)為當(dāng)前目錄 |
| system() | 在shell中執(zhí)行command指定的命令 |
| sep | 返回特定操作系統(tǒng)使用的分隔符 |
| name | 返回操作系統(tǒng)的名稱。在Windows上返回nt,在Linux上返回posix |
| environ | 返回操作系統(tǒng)的環(huán)境變量 |
| linesep | 返回操作系統(tǒng)使用的換行符 |
| pathsep | 返回操作系統(tǒng)環(huán)境變量的分隔符 |
| curdir | 返回當(dāng)前目錄(.) |
| pardir | 返回上級目錄(..) |
2.2 os.path模塊
os.path模塊提供了關(guān)于路徑操作的相關(guān)功能,常用方法如下:
| 方法名 | 描述 |
| abspath(path) | 返回path的絕對路徑 |
| basename(path) | 返回path的最后一個(gè)部分。即path中操作系統(tǒng)分隔符(/或\等)最后一次出現(xiàn)位置后面的內(nèi)容。如果path以操作系統(tǒng)分隔符結(jié)尾,則返回空字符串 |
| commonpath(paths) | 參數(shù)paths為路徑的序列,返回最長的公共子路徑 |
| dirname(path) | 返回path的目錄部分 |
| exists(path) | 判斷路徑是否存在,存在返回True,否則返回False |
| getatime(path) | 返回文件或目錄的最后訪問時(shí)間 |
| getmtime(path) | 返回文件或目錄的最后修改時(shí)間 |
| getsize(path) | 返回文件的大小,以字節(jié)為單位 |
| isabs(path) | 判斷path是否為絕對路徑,是返回True,否則返回False |
| isdir(path) | 判斷path是否為存在的目錄,是返回True,否則返回False |
| isfile(path) | 判斷path是否為存在的文件,是返回True,否則返回False |
| join(path,*paths) | 連接所有的path,以當(dāng)前操作系統(tǒng)的分隔符分隔,并返回。空path(除了最后一個(gè))將會丟棄。如果最后一個(gè)path為空,則以分隔符作為結(jié)尾。如果其中的一個(gè)path為絕對路徑,則絕對路徑之前的路徑都會丟棄,從絕對路徑處開始連接 |
| split(path) | 將path分割成一個(gè)元組,元組含有兩個(gè)元素,第2個(gè)元素為path的最后一個(gè)部分,第一個(gè)元素為剩余之前的部分。(dirname與basename) |
?
2.3 shutil模塊
shutil模塊提供了高級操作文件的方式。通過該模塊提供的功能,可以快捷方便的對文件或目錄執(zhí)行復(fù)制,移動等操作。常用方法如下:
| 方法名 | 描述 |
| copy(src,dst) | 復(fù)制文件,返回復(fù)制后的文件路徑。src指定要復(fù)制的文件,如果dst是一個(gè)存在的目錄,則將文件復(fù)制到該目錄中,文件名與src指定的文件名一致,否則,將src復(fù)制到dst指定的路徑中,文件名為dst中指定的文件名 |
| copy2(src,dst) | 與copy函數(shù)類似,但是copy函數(shù)不會保留文件的元信息,例如創(chuàng)建時(shí)間,最后修改時(shí)間等。copy2函數(shù)會盡可能保留文件的元信息 |
| copytree(src,dst) | 復(fù)制一個(gè)目錄,目錄中的文件與子目錄也會遞歸實(shí)現(xiàn)復(fù)制,返回復(fù)制后的目錄路徑。src指定要復(fù)制的目錄,dst指定復(fù)制后的目標(biāo)目錄,如果dst已經(jīng)存在,則會產(chǎn)生異常 |
| rmtree(path) | 刪除path指定的目錄,目錄中的子目錄與文件也會一并刪除 |
| move(src,path) | 將文件或目錄移動到另外一個(gè)位置,src指定文件或目錄的路徑,當(dāng)src為目錄時(shí),會將該目錄下所有的文件與子目錄一同移動(遞歸)。dst指定移動的目標(biāo)文件或目錄 |
使用copytree(src,dst)復(fù)制目錄時(shí),可以結(jié)合ignore_patterns函數(shù)對目錄下的文件與子目錄進(jìn)行排除。如:shutil.copytree("abc", "def", ignore=shutil.ignore_patterns("*.txt"))ignore參數(shù)指定忽略的文件或目錄,這樣,所有名稱以txt結(jié)尾的文件或目錄將不會復(fù)制到目標(biāo)目錄中。
?
2.4 glob模塊
glob模塊提供列舉目錄下文件的方法,支持通配符*,?與[?]。常用方法如下:
glob(pathname,?*, recursive=False)
返回所有匹配pathname的文件與目錄名稱構(gòu)成的列表,列表中元素的順序是沒有規(guī)律的。如果recursive值為True,則可以使用**匹配所有文件與目錄,包括所有子目錄中的文件與目錄(遞歸)。
pathname中可以指定通配符:①*:匹配任意0個(gè)或多個(gè)字符②?:匹配任意1個(gè)字符③[]:匹配[]內(nèi)的任意一個(gè)字符,支持使用“-”區(qū)間的表示。例如[0-9]則匹配0到9任何一個(gè)字符,[a-f]則匹配a-f之間的任何一個(gè)字符
iglob(pathname, *, recursive=False)與glob功能相同,只是返回一個(gè)迭代器而不是列表。
?
3 序列化
3.1 csv
CSV(Comma Separated Values),是一種存文本格式的文件,文件中各個(gè)元素值通常使用逗號(,)進(jìn)行分隔,但這不是必須的,擴(kuò)展名為.csv。可以使用csv模塊來操作csv類型的文件。
# scv模塊 import csv # 寫入csv文件,在寫入的時(shí)候最好將newline設(shè)置為"",不然會產(chǎn)生空行 with open("E:/test/a.csv","wt",newline="") as f:# writer函數(shù)返回一個(gè)寫入器對象,能向參數(shù)指定的文件中寫入數(shù)據(jù)writer = csv.writer(f)writer.writerow(["張三","18","男"])writer.writerow(["李四","20","男"])# 一次寫入多行記錄的話提供一個(gè)二維列表,每個(gè)一維列表就是一條記錄writer.writerows([["王五","25","男"],["趙六","30","男"]]) # 讀取csv文件 with open("E:/test/a.csv","rt") as f:# reader函數(shù)返回一個(gè)讀取器對象(是可迭代對象),能夠讀取csv文件中的數(shù)據(jù)內(nèi)容reader = csv.reader(f)for lines in reader:print(lines)3.2 json
(1)什么是json
JSON(JavaScript Object Notation),是一種輕量級的數(shù)據(jù)交換格式。json采用的是一組鍵與值的映射,鍵與值之間使用“:”進(jìn)行分隔,而鍵值對之間使用“,”進(jìn)行分隔。json文件中的類型可以是:
| 類型 | 描述 |
| 對象類型 | 使用{}表示 |
| 數(shù)組類型 | 使用[]表示 |
| 字符串類型 | 使用雙引號表示 |
| 布爾類型 | true或false |
| 數(shù)值類型 | 整數(shù)與浮點(diǎn)數(shù) |
格式如下:
{"desc": "json","data": {"content": ["content1", "content2", "content3"],"annotation": "注釋"} }(2)dump與load處理程序,dumps與loads序列化與反序列化
可以通過json類型的數(shù)據(jù)進(jìn)行對象的序列化與反序列化。
序列化:將對象類型轉(zhuǎn)換成字符串的形式。
反序列化:將序列化的字符串恢復(fù)為對象類型。
通過序列化與反序列化,我們就可以方便的對復(fù)雜的對象進(jìn)行存儲與恢復(fù)(因?yàn)槲募x寫只支持字符串類型),或者通過網(wǎng)絡(luò)進(jìn)行傳輸,將對象共享給遠(yuǎn)程的其他程序使用。
# json文件提供不同項(xiàng)目之間的數(shù)據(jù)交換 import json data = {"desc": "json","data": {"content": ["content1", "content2", "content3"],"annotation": "注釋"} } with open("E:/test/a.json","wt") as f:# 向文件中寫入json格式數(shù)據(jù),參數(shù)1:要寫入的數(shù)據(jù),參數(shù)2:文件對象# json寫入數(shù)據(jù)時(shí),默認(rèn)只顯示ascii字符集的字符,非ascii字符集的字符需要轉(zhuǎn)義# 指定ensure_ascii=False可以顯示,非ascii字符集的字符json.dump(data,f,ensure_ascii=False) with open("E:/test/a.json","rt") as f:# 讀取json數(shù)據(jù),恢復(fù)成一個(gè)字典data = json.load(f)print(type(data))print(data) # 通過序列化與反序列化,可以實(shí)現(xiàn)不同項(xiàng)目之間的數(shù)據(jù)交換 # 序列化 d = json.dumps(data,ensure_ascii=False) print(type(d)) print(d) # 反序列化 d2 = json.loads(d) print(type(d2)) print(d2)Python中的數(shù)據(jù)類型與json格式的數(shù)據(jù)類型并非完全相符,因此,在進(jìn)行轉(zhuǎn)換的時(shí)候,可能會進(jìn)行一些映射處理,如下(json?-> Python):
布爾類型(true與false)映射Python中布爾類型(True與False)。
空值類型(null)映射為None。
整數(shù)與浮點(diǎn)類型映射為整數(shù)(int)與(float)類型。
字符串類型映射為字符串(str)類型。
數(shù)組類型([])映射為列表(list)類型。
對象類型(object)映射為字典(dict)類型
# json文件提供不同項(xiàng)目之間的數(shù)據(jù)交換 import json data = {"布爾類型":False,"空值類型":None,"整數(shù)與浮":2,"浮點(diǎn)類型":2.2,"字符串類型":"a","數(shù)組類型":[1,2,3],"對象類型":{"a":1,"b":2} } d = json.dumps(data,ensure_ascii=False) print(d) d2 = json.loads(d) print(d2)(3)自定義類型序列化
json在序列化時(shí),不能序列化我們自定義的類型。如果我們需要自定義的類型也能夠序列化,可以定義一個(gè)編碼類,該類繼承json.JSONEncoder,實(shí)現(xiàn)類中的default方法,指定序列化的方式,同時(shí),在調(diào)用序列化方法時(shí)(dump或dumps),使用cls參數(shù)指定我們定義的編碼類。
# 自定義類型序列化 import json # 自定義的編碼類繼承json.JSONEncoder類型 class StudentEncoder(json.JSONEncoder):# 實(shí)現(xiàn)default方法,給出序列化形式,參數(shù)o為序列化對象def default(self, o):if isinstance(o,Student):# 將Student轉(zhuǎn)換成可序列化對象# return {"name":o.name,"age":o.age}# 返回所有屬性構(gòu)成字典return o.__dict__else:# 不是Student類型,調(diào)用父類的default翻翻產(chǎn)生錯(cuò)誤信息return super().default(0) class Student:def __init__(self,name,age):self.name = nameself.age =age s = Student("refuel",18) print(s.__dict__) # cls參數(shù)指定序列化需要用到的編碼類 jsonstr = json.dumps(s,cls=StudentEncoder) print(jsonstr)?
3.3 pickle
pickle模塊也能序列化類型。在序列化自定義類型上,pickle可以比json模塊更加方便(不需要定義類似的編碼器類)。pickle與json在序列化上的區(qū)別如下:
| 序列化 | json | pickle |
| 序列化格式 | 文本格式,可進(jìn)行正常查看。 | 二進(jìn)制格式,不方便查看。 |
| 序列化類型的支持 | 支持一部分內(nèi)建的類型,如果需要序列化自定義類型,需要編寫編碼類。 | 支持非常廣泛的類型,包括自定義類型,不需要編寫編碼類。 |
| 適用廣泛性 | 適用廣泛,對于序列化的內(nèi)容可以用于Python語言之外的程序中進(jìn)行反序列化。 | 適用受限,只能用于Python程序中,其他語言的程序無法反序列化。 |
4 上下文管理器
4.1 自定義上下文管理器
with語句跟隨的表達(dá)式會返回一個(gè)上下文管理器,該上下文管理器中定義相關(guān)方法,在with開始執(zhí)行與退出時(shí)會調(diào)用,也就是說,上下文管理器為with提供一個(gè)執(zhí)行環(huán)境。
__enter__(self):with語句體開始執(zhí)行時(shí),會調(diào)用該方法。可以在該方法中執(zhí)行初始化操作,返回值會賦值給with語句中as后面的變量
__exit__(self, exc_type, exc_val, exc_tb):with語句體執(zhí)行結(jié)束后,會調(diào)用該方法。我們在__enter__方法中執(zhí)行的初始化,就可以在該方法中執(zhí)行相關(guān)的清理,如,文件的關(guān)閉,線程鎖的釋等。實(shí)現(xiàn)finally語句同樣的功能。exc_type:產(chǎn)生異常的類型;exc_val:產(chǎn)生異常類型的對象;exc_tb:traceback類型的對象,包含了異常產(chǎn)生位置的堆棧調(diào)用信息。如果在with語句體中沒有產(chǎn)生異常,相關(guān)參數(shù)為None。
對于with,也可以關(guān)聯(lián)兩個(gè)上下文管理器,如:
with Manager1() as m1, Manager2 as m2:語句這相當(dāng)于:with Manager1() as m1:with Manager2() as m2:語句?
class MyManager:def __enter__(self):print("進(jìn)入with語句體")# return selfreturn "__enter__返回值賦值給as后變量"def __exit__(self, exc_type, exc_val, exc_tb):print("離線with語句體")print(exc_type)print(exc_val)print(exc_tb) with MyManager() as f:# print(f)raise Exception("with中存在異常")4.2?@contextmanager裝飾器
contextlib模塊中,定義了@contextmanager裝飾器,該裝飾器可以用來修飾一個(gè)生成器,從而將生成器變成一個(gè)上下文管理器,從而可以省略編寫完整的上下文管理器類。
在@contextmanager修飾的生成器中,yield之前的語句會在進(jìn)入with語句體時(shí)執(zhí)行(相當(dāng)于__enter__方法),而yield之后的語句會在離開with語句體時(shí)執(zhí)行(相當(dāng)于__eixt__方法)。
with后的表達(dá)式會返回生成器對象(假設(shè)為gen_obj),進(jìn)入with語句體時(shí),內(nèi)部會調(diào)用next函數(shù),用來激活生成器對象,進(jìn)而執(zhí)行生成器的函數(shù)體next(gen_obj)
從而令生成器對象執(zhí)行。yield產(chǎn)生的值則會賦值給with語句as后的變量(相當(dāng)于__enter__方法的返回值)。
當(dāng)with語句體結(jié)束時(shí),如果with語句體沒有產(chǎn)生異常,則繼續(xù)調(diào)用next,令生成器從之前yield暫停的位置處繼續(xù)執(zhí)行(這相當(dāng)于實(shí)現(xiàn)__exit__方法)。如果with語句體產(chǎn)生異常,該異常會在生成器函數(shù)體yield的位置拋出。而如果生成器函數(shù)體沒有處理該異常,將會導(dǎo)致yield之后的語句不會得到執(zhí)行,這相當(dāng)于是沒有成功的執(zhí)行__exit__方法。
# @contextManager修飾一個(gè)生成器,裝飾成上下文管理器 from contextlib import contextmanager # yield之前的語句會在進(jìn)入with環(huán)境時(shí)執(zhí)行(相當(dāng)于__enter__方法) # yield產(chǎn)生的值賦值給as后面的變量(相當(dāng)與__enter__方法的返回值) # 離開with環(huán)境,執(zhí)行yield之后的語句(相當(dāng)于是__exit__方法) @contextmanager def f():print("進(jìn)入with環(huán)境")# 如果with語句體中產(chǎn)生異常,該異常會傳播到y(tǒng)ield位置處,后面的語句不得到執(zhí)行,# 所以要使用try-finally操作.根據(jù)情況捕獲,相當(dāng)于實(shí)現(xiàn)了__exit__方法的返回值try:yield "產(chǎn)生的值賦值給as后面的變量"except:passfinally:print("離開with環(huán)境") with f() as f:# print(f)raise Exception("異常")總結(jié)
以上是生活随笔為你收集整理的Python基础(十)--文件相关的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql多种join_MySQL的几种
- 下一篇: python 强制结束线程_在pytho