在我們編寫Python代碼時,我們需要經常使用各種資源,例如文件、網絡連接、進程等等。這些資源通常需要進行釋放,否則我們的程序會產生一些意想不到的後果,例如文件句柄泄漏、網絡連接不斷增加以及多餘的進程,這些都會導致程序出現性能瓶頸,甚至崩潰。
在Python中,有一個非常優雅、高效、節約時間的資源釋放方式,那就是使用contextlib中的contextmanager和closing函數。
一、contextmanager的使用
contextmanager是Python提供的一種非常優雅、高效和pythonic的資源管理機制,它可以很好地處理那些需要進入和退出前後代碼塊的情況,例如文件和線程同步對象。
在使用contextmanager時,我們需要用到裝飾器,將一個單獨的函數變成一個上下文管理器:
@contextlib.contextmanager
def my_context_manager():
# 初始化代碼
yield
# 釋放資源代碼
在這個函數中,我們需要用到yield,它會將程序的控制權交給with語句中的代碼塊。當我們退出with塊時,yield會將程序的控制權返回到my_context_manager函數,使得我們能夠在退出前執行必要的代碼。從而完成釋放資源的工作。
以下是一個簡單的例子,用contextmanager管理打開的文件:
import contextlib
@contextlib.contextmanager
def open_file(filename, mode='r'):
f = open(filename, mode)
try:
yield f
finally:
f.close()
我們使用with語句打開文件:
with open_file('sample.txt') as f:
print(f.read())
這段代碼可以保證在退出with塊時,文件會自動關閉。
二、closing函數的使用
與contextmanager相似,closing函數也可以幫助我們優雅地處理資源,例如網絡連接等。
在標準庫中提供了一個名為closing的函數,它可以將對象封裝給上下文管理器:
from contextlib import closing
import urllib
with closing(urllib.request.urlopen('http://www.example.com')) as page:
for line in page:
print(line)
這段代碼可以保證在退出with塊時,網絡連接會自動關閉。
三、使用示例
接下來,我們將演示一個使用contextmanager和closing函數的示例代碼。
我們編寫一個管理數據庫連接的上下文管理器:
import sqlite3
from contextlib import contextmanager
@contextmanager
def sqlite_manager(database):
conn = sqlite3.connect(database)
try:
yield conn
finally:
conn.close()
接下來,我們編寫一個函數,通過sqlite_manager上下文管理器連接數據庫,並查詢數據:
def query_database(database, query):
with sqlite_manager(database) as conn:
cursor = conn.cursor()
cursor.execute(query)
result = cursor.fetchall()
for row in result:
print(row)
最後,我們通過closing函數連接web api,並從中獲取數據:
import json
import urllib.request
with closing(urllib.request.urlopen('http://jsonplaceholder.typicode.com/posts/1/comments')) as page:
result = json.loads(page.read().decode('utf-8'))
for item in result:
print(item)
這個示例演示了如何使用contextmanager和closing函數優雅地管理資源,使代碼更加健壯、可讀性更高、效率更高,同時也更加節省時間。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/279000.html