Python contextmanager.__exit__ 用法详解及示例
Python contextlib模块简介
在Python中,contextlib模块提供了一些用于创建上下文管理器的工具。上下文管理器是一种实现了 __enter__() 和 __exit__() 方法的对象,用于管理资源的分配和释放。__exit__() 方法在代码块结束后自动调用,用于处理任何异常或清理操作。
contextmanager 的 __exit__ 语法
contextmanager 是 contextlib 模块中的装饰器,用于将一个生成器函数转换为上下文管理器。被 contextmanager 装饰的生成器函数应该使用 yield 语句将控制权传递给 __enter__() 方法,并使用 yield 返回一个值作为 __enter__() 方法的返回值。__exit__() 方法不需要在生成器函数中定义。
__exit__() 方法的语法如下:
def __exit__(self, exc_type, exc_value, traceback):
...
其中,三个参数分别表示异常类型、异常值和异常追踪信息。
示例
下面是三个使用 contextmanager 的示例,分别用于操作文件、数据库和网络连接:
1. 文件处理
import contextlib
@contextlib.contextmanager
def open_file(file_name):
try:
file = open(file_name, 'r')
yield file
finally:
file.close()
with open_file('example.txt') as f:
data = f.read()
print(data)
上述示例定义了一个上下文管理器函数 open_file(),用于打开指定文件并返回文件对象。在 try 块中,使用 yield 语句将控制权传递给 __enter__() 方法,并在 finally 块中进行资源清理操作。
2. 数据库连接
import contextlib
import sqlite3
@contextlib.contextmanager
def get_db_connection(database):
try:
conn = sqlite3.connect(database)
yield conn
finally:
conn.close()
with get_db_connection('example.db') as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
for row in rows:
print(row)
上述示例定义了一个上下文管理器函数 get_db_connection(),用于从指定的 SQLite 数据库获得数据库连接对象。在 try 块中,使用 yield 语句将控制权传递给 __enter__() 方法,并在 finally 块中进行资源清理操作。
3. 网络连接
import contextlib
import socket
@contextlib.contextmanager
def open_socket(host, port):
try:
sock = socket.socket()
sock.connect((host, port))
yield sock
finally:
sock.close()
with open_socket('www.example.com', 80) as sock:
sock.send(b'GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n')
response = sock.recv(4096)
print(response.decode())
上述示例定义了一个上下文管理器函数 open_socket(),用于打开一个与指定主机和端口的套接字连接。在 try 块中,使用 yield 语句将控制权传递给 __enter__() 方法,并在 finally 块中进行资源清理操作。
这三个示例展示了 contextmanager 的 __exit__ 语法的使用方式,通过使用上下文管理器,可以更方便地处理资源的分配和释放。
极客教程