1. 程式人生 > 實用技巧 >with與“上下文管理器”——Python

with與“上下文管理器”——Python

with與“上下文管理器”

1. with語句的使用

向檔案中寫入資料的示例程式碼:

# 1、以寫的方式開啟檔案
 f = open("1.txt", "w")
 # 2、寫入檔案內容
 f.write("hello world")
 # 3、關閉檔案
 f.close()

程式碼說明:

  • 檔案使用完後必須關閉,因為檔案物件會佔用作業系統的資源,並且作業系統同一時間能開啟的檔案數量也是有限的

這種寫法可能出現一定的安全隱患,錯誤程式碼如下:

 # 1、以讀的方式開啟檔案
 f = open("1.txt", "r")
 # 2、讀取檔案內容
 f.write("
hello world") # 3、關閉檔案 f.close()

執行:

Traceback (most recent call last):
  File "/home/python/Desktop/test/xxf.py", line 4, in <module>
    f.write("hello world")
io.UnsupportedOperation: not writable

程式碼說明:

  • 由於檔案讀寫時都有可能產生IOError,一旦出錯,後面的f.close()就不會呼叫
  • 為了保證無論是否出錯都能正確地關閉檔案,我們可以使用try ... finally來解決

安全寫法, 程式碼如下:

try:
    # 1、以讀的方式開啟檔案
    f = open("1.txt", "r")
    # 2、讀取檔案內容
    f.write("xxxxx")

except IOError as e:
    print("檔案操作出錯", e)

finally:
    # 3、關閉檔案
    f.close()

執行結果:

檔案操作出錯 not writable

這種方法雖然程式碼執行良好,但是缺點就是程式碼過於冗長,並且需要新增try-except-finally語句,不是很方便,也容易忘記.

在這種情況下,Python提供了 with 語句的這種寫法,既簡單又安全,並且 with 語句執行完成以後自動呼叫關閉檔案操作,即使出現異常也會自動呼叫關閉檔案操作。

with 語句的示例程式碼:

# 1、以寫的方式開啟檔案
with open("1.txt", "w") as f:
    # 2、讀取檔案內容
    f.write("hello world")

2. 上下文管理器

一個類只要實現了__enter__()和__exit__()這個兩個方法,通過該類建立的物件我們就稱之為上下文管理器

上下文管理器可以使用 with 語句,with語句之所以這麼強大,背後是由上下文管理器做支撐的,也就是說剛才使用 open 函式建立的檔案物件就是就是一個上下文管理器物件。

自定義上下文管理器類,模擬檔案操作:

定義一個File類,實現__enter__() 和 __exit__()方法,然後使用 with 語句來完成操作檔案, 示例程式碼:

class File(object):

    # 初始化方法
    def __init__(self, file_name, file_model):
        # 定義變數儲存檔名和開啟模式
        self.file_name = file_name
        self.file_model = file_model

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

    # 下文方法
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("進入下文方法")
        self.file.close()


if __name__ == '__main__':

    # 使用with管理檔案
    with File("1.txt", "r") as file:
        file_data = file.read()
        print(file_data)

執行:

進入上文方法
hello world
進入下文方法

程式碼說明:

  • __enter__表示上文方法,需要返回一個操作檔案物件
  • __exit__表示下文方法,with語句執行完成會自動執行,即使出現異常也會執行該方法。

3. 上下文管理器的另外一種實現方式

假如想要讓一個函式成為上下文管理器,Python 還提供了一個 @contextmanager 的裝飾器,更進一步簡化了上下文管理器的實現方式。

通過 yield 將函式分割成兩部分,yield 上面的語句在__enter__方法中執行,yield 下面的語句在__exit__方法中執行,緊跟在 yield 後面的引數是函式的返回值。

# 匯入裝飾器
from contextlib import contextmanager


# 裝飾器裝飾函式,讓其稱為一個上下文管理器物件
@contextmanager
def my_open(path, mode):
    try:
        # 開啟檔案
        file = open(file_name, file_mode)
        # yield之前的程式碼好比是上文方法
        yield file
    except Exception as e:
        print(e)
    finally:
        print("over")
        # yield下面的程式碼好比是下文方法
        file.close()

# 使用with語句
with my_open('out.txt', 'w') as f:
    f.write("hello , the simplest context manager")

4. 小結

  • Python 提供了 with 語句用於簡化資源釋放的操作,使用 with 語句操作建立在上下文管理器(實現__enter__和__exit__)的基礎上
  • Python 還提供了一個 @contextmanager 裝飾器,更進一步簡化上下管理器的實現,讓一個函式可以成為上下文管理器,結合 with 語句來使用