Python 中 open() 方法既能直接返回也能通過with語句當作上下文管理器使用是怎麼做到的?
如題。簡單看了下io.py部分的源碼,只看到了open的定義是直接返回對象,沒有看到是如何實現上下文管理器的。Google了半天也沒有結果。求知乎大神解答!
前段時間果殼 Python 開發面試被問到了這個問題
實現某個對象可以用 with 來管理,只需要改寫 __enter__ 和 __exit__ 這兩個 magic method 即可
另外你說你在 io.py 源碼里沒找到,大哥讀代碼要仔細啊
io.py 里的 IO 函數都是從 _pyio.py 里 import 進來的,然後在 _pyio.py 的第 140 行 到 147 行有這麼一段注釋
open() returns a file object whose type depends on the mode, and
through which the standard file operations such as reading and writingare performed. When open() is used to open a file in a text mode ("w",
"r", "wt", "rt", etc.), it returns a TextIOWrapper. When used to opena file in a binary mode, the returned class varies: in read binarymode, it returns a BufferedReader; in write binary and append binarymodes, it returns a BufferedWriter, and in read/write mode, it returnsa BufferedRandom.
所以 open() 這個函數在不同模式下會返回不同的對象,包括 TextIOWrapper/BufferedReader/BufferedWriter 這三種
繼續看上面這三個類的定義,發現這幾個類還繼承了其他的幾個類,這裡我就不領著你看了,直接用 Visio 畫了個類層次示意圖,如下
其中藍色矩形表示 class,藍色連線表示繼承關係,藍色連線上的數字表示這個繼承關係的代碼在源碼中的哪一行
可以看到 open() 函數所返回的幾個 class,最終都繼承於 IOBase 這個 class,而在這個 class 中,就實現了 __enter__() 和 __exit() 兩個 magic method,具體代碼位於 _pyio.py 的第 428 行到 437 行
### Context manager ###
def __enter__(self):
"""Context management protocol. Returns self."""
self._checkClosed()
return self
def __exit__(self, *args):
"""Context management protocol. Calls close()"""
self.close()
只要有__enter__和__exit__方法,就能用在with語句里,open返回的對象有這兩個方法,就可以了,不必在open方法內做什麼手腳。
你google context manager就有結果了
Python 的上線文管理器使用with關鍵字,用來定義with後面這個縮進級別,進入和跳出的行為,是語法糖的一種。open是一個調用用於實例化file類的函數,而file類只不過是一個擁有__enter__和__exit__(這種前後都有兩個下劃線的在Python中叫做「魔法方法」,除了這兩個還有很多,有興趣可以去查一下)的類,用在with中時,程序會自動在進出這個程序塊時調用這兩個函數,如果沒用with就要手動管理,自己調用close()。如果想要自己實現類似的功能,用回調就,或者單獨封裝成裝飾器(裝飾器其實也是Python的一種語法糖)都可以。
跟Java的Closeable一樣 定義好釋放資源的方式 通過語法糖隱藏部分重複代碼
推薦閱讀:
※C++派生類怎樣進行文件讀寫?
※如何理解面向組合子編程?
※C語言的設計模式有哪些?
※面向對象、面向服務、面向組件三種編程模式有什麼區別?分別適用於哪些領域的開發?