在我们编写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函数优雅地管理资源,使代码更加健壮、可读性更高、效率更高,同时也更加节省时间。