with open() as 的用法 和 with上下文管理器(Context manager)

AH_CFL發表於2020-11-10

with open() as 的用法 和 with上下文管理器(Context manager)


一、基礎讀寫:

讀⽂件:

1、以讀的⽅式開啟⽂件

f = open(“1.txt”, “r”)

2、讀取⽂件內容

str = f.read()

print(str)

3、關閉⽂件

f.close()

寫⽂件:

1、以寫的⽅式開啟⽂件

f = open(“2.txt”, “w”)

2、寫⼊⽂件內容

str = f.write(“Welcome to 北京!”)

3、關閉⽂件

f.close()


二、 錯誤程式碼示範:

這種⽅式存在的問題是什麼?

1、以讀的⽅式開啟⽂件

f = open(“1.txt”, “r”)

2、讀取⽂件內容

f.write(“xxxxx”)

f.close()

由於⽂件讀寫時都有可能產⽣ IOError ,⼀旦出錯,後⾯的 f.close() 就不會調⽤。

三、優化程式碼:

1)為了保 證⽆論是否出錯都能正確地關閉⽂件,我們可以使⽤ try … finally 來實現:

try:

1、以讀的⽅式開啟⽂件

f = open(“1.txt”, “r”)

2、讀取⽂件內容

f.write(“xxxxx”)

except IOError as e:

print(“⽂件操作出錯”, e)

finally:

f.close()

2)Python引⼊了 with 語句來⾃動幫我們調⽤ close() ⽅法:

try:

1、以讀的⽅式開啟⽂件

with open(“1.txt”, “r”) as f:

2、讀取⽂件內容

f.write(“xxxxx”)

except IOError as e:

print(“⽂件操作出錯”, e)

》這和前⾯的 try … finally 是⼀樣的,但是程式碼更佳簡潔,並且不必調⽤ f.close() ⽅法。

》使⽤ with 關鍵字。open ⽅法的返回值賦值給變數 f,當離開 with 程式碼塊 的時候,系統能夠⾃動調⽤ f.close() ⽅法


四、 with 的原理之上下文管理器

with 的原理前要涉及到另 外⼀個概念,就是上下⽂管理器(Context Manager)。

1)上下文理解成(語言)環境就可以,(⽽且上下⽂雖然叫上下⽂,但是程式⾥⾯⼀ 般都只有上⽂⽽已,只是叫的好聽叫上下⽂。。

2)上下⽂管理器本質就是能夠⽀持with操作。 任何實現了__enter__() 和 __exit__()⽅法的物件都可稱之為上下⽂管理器,上下⽂管理器物件可以使 ⽤ with 關鍵字。顯然,⽂件(file)物件也實現了上下⽂管理器協議。

一、程式碼演示:
"""
類:  MyFile()
類方法:
   1. __enter__()  上文方法
   2. __exit__()   下文方法
   3. __init__()   方法,接收引數並且初始化

目的:驗證上下⽂管理器(Context Manager)
   with MyFile('hello.txt', 'r') as file:
       file.read()
   
"""

class MyFile(object):

   # 1. __enter__()  上文方法
   def __enter__(self):
       print("進入上文....")
       # 1,開啟檔案 
       self.file = open(self.file_name, self.file_model)
       # 2,返回開啟的檔案資源
       return self.file

   # 2. __exit__()   下文方法
   def __exit__(self, exc_type, exc_val, exc_tb):
       print("進入下文....")
       # 關閉檔案資源
       self.file.close()

   # 3. __init__()   方法,接收引數並且初始化
   def __init__(self, file_name, file_model):
       # 區域性變數定義成例項屬性 -> 在類裡面呼叫
       # 儲存檔名和檔案開啟模式 -> 到例項屬性中
       self.file_name = file_name
       self.file_model = file_model


if __name__ == '__main__':

   with MyFile("hello.txt", "r") as file:
       # 開始讀取檔案
       file_data = file.read()
       print(file_data)
       

執行結果:

進入上文....
hello,python!
進入下文.... 

__enter__()⽅法返回資源物件,這⾥就是你將要開啟的那個⽂件物件,__exit__()⽅法做⼀些清除⼯作。

因為 File 類實現了上下⽂管理器,所以就可以使⽤ with 語句了。

二、實現上下⽂管理器的另外⽅式

Python 提供了⼀個 contextmanager 模組的裝飾器@contextmanager,更進⼀步簡化了上下⽂管理器的實現⽅式。通過 yield 將函式分割成兩部分,yield 之前的語句在__enter__ ()⽅法中執⾏,yield 之後的語句在__exit__()⽅法中執⾏。緊跟在 yield 後⾯的值是 函式的返回值。

裝飾器:不修改(待修飾函式)原函式的程式碼,增加新的功能(方法)

"""
思路:
    def myopen(file_name,file_model)

            上文(開啟資源)
            yield
            下文(關閉資源)

裝飾器裝飾函式的步驟:
1. 匯入模組 from contextlib import contextmanager
2. 開始裝飾 @contextmanager


"""
from contextlib import contextmanager


@contextmanager
def myopen(file_name,file_model):

    print("進入上文")
    # 1.開啟檔案
    file = open(file_name,file_model)
    # 2.返回資源
    yield file
    print("進入下文")
    # 下文
    # 3. 關閉資源
    file.close()


with myopen("hello.txt", "r") as file:
    file_data = file.read()
    print(file_data)
     

執行結果:

進入上文....
hello,python!
進入下文.... 

五、 總結

1)Python 提供了 with 語法⽤於簡化資源操作的後續清除操作,實現原理建⽴在上下⽂管理器協議 (__enter____exit__)之上

2)with使⽤程式碼中如果在開啟過程中發⽣異常,需要使⽤try-except進⾏捕獲

3)Python 還提供了⼀個 contextmanager 裝飾器,更進⼀步簡化上下管理器的實現⽅式。


六、應用with open() as

1.建立 寫檔案
request_data = urllib.request.urlopen(img_url)

#在(指定路徑下 )--> 建立檔案 --> 準備儲存
 
with open('/home/cfl/Desktop/+ file_name, "wb") as file:

#在(當前目錄) --> 建立檔案 --> 準備儲存

with open(file_name, "wb") as file:
          while True:
                file_data = request_data.read(1024)
                if file_data:
                    file.write(file_data)
                else:
                    break
2.開啟 讀檔案

recv_data = new_client_socket.recv(1024)
file_name = recv_data.decode()
#根據檔名讀取檔案內容
try:
with open(file_name, “rb”) as file:
把讀取的檔案內容傳送給客戶端(迴圈)
while True:>
file_data = file.read(1024)
判斷是否讀取到了檔案的末尾
if file_data:
傳送檔案
new_client_socket.send(file_data)
else:
break
except Exception as e:
print(“檔案%s下載失敗” % file_name)
else:
print(“檔案%s下載成功” % file_name

相關文章