對於系統資源如文件、數據庫連接、socket 而言,應用程序打開這些資源並執行完業務邏輯之後,必須做的一件事就是要關閉(斷開)該資源。
如何正確的關閉一個文件呢?
1.普通版
def test0():
f = open("1.txt", "w")
f.write("0000")
f.close()
2.進階版
def test1():
f = open("1.txt", "w")
try:
f.write("111111")
except Exception:
print("ERROR")
finally:
f.close()
3.高級版
def test2():
with open("1.txt", "w") as f:
f.write("2222")
使用with關鍵字的方法更爲簡潔,它的實現原理是什麼,這就涉及到上下文管理器。
任何實現了 __enter__()
和__exit__()
方法的對象都可稱之爲上下文管理器
4.用類還原with的實現原理
class Test4(object):
def __init__(self, file_name, mode):
self.file_name = file_name
self.mode = mode
def __enter__(self):
self.f = open(self.file_name, self.mode)
return self.f
def __exit__(self,*args):
self.f.close()
with Test4("1.txt", "w") as f:
f.write("4444")
"""
首先Test4("1.txt", "w")初始化實例對象,
然後with會尋找類中是否有__enter__ 和 __exit__,
如果有則調用__enter__函數,
最後__enter__() 方法返回資源對象,這裏就是你將要打開
的那個文件對象,__exit__() 方法處理一些清除工作。
"""
5.使用contextmanager裝飾器,實現with功能
from contextlib import contextmanager
"""
Python 還提供了一個 contextmanager 的裝飾器,更進一步簡化
了上下文管理器的實現方式。通過 yield 將函數分割成兩部分,yield 之前的
語句在 __enter__ 方法中執行,yield 之後的語句在 __exit__ 方法中執行。
緊跟在 yield 後面的值是函數的返回值。
"""
@contextmanager
def test5(path, mode):
f = open(path, mode)
yield f
f.close()
with test5('out.txt', 'w') as f:
f.write("5555")
總結:
Python 提供了 with 語法用於簡化資源操作的後續清除操作,是 try/finally 的替代方法,實現原理建立在上下文管理器之上。此外,Python 還提供了一個 contextmanager 裝飾器,更進一步簡化上下管理器的實現方式。