引言
使用 with
语句和上下文管理器是 Python 中管理资源的优雅方式。上下文管理器确保在代码块执行前和执行后执行一些操作,常用于管理文件、数据库连接、线程锁等资源。
什么是with
语句和上下文管理器
with
语句用于简化资源管理,它会在代码块执行前调用上下文管理器的 __enter__
方法,并在代码块执行后调用 __exit__
方法。上下文管理器确保无论是否发生异常,资源都会被正确释放。
基本语法如下:
with open('text.log','r',encoding='utf-8') as file:
for line in file:
print(line.strip())
使用with
管理文件操作
文件操作是with
语句最常见的应用场景之一,使用with
语句可以确保文件在使用完毕后自动关闭,不需要收到您调用文件关闭函数,即时在操作过程中发生异常。
代码示例可参照上面的代码
open
函数返回一个文件对象,with
语句调用文件对象的__enter__
方法打开文件,并在代码块结束后调用__exit__
方法关闭文件。
编写自定义上下文管理器
我们可以使用__enter__
和__exit__
方法实现一个自定义的上下文管理器,下面示例实现一个简单的文件管理器
class FileManager:
def __init__(self,filename,mode):
self.filename = filename
self.mode = mode
self.file = None
def is_closed(self):
if self.file:
return self.file.closed
def __enter__(self):
self.file = open(self.filename,self.mode,encoding='utf-8')
return self.file
def __exit__(self,exc_type,exc_value,traceback):
if self.file:
self.file.close()
# 处理异常(可选)
if exc_type:
print(f"Exception type: {exc_type}")
print(f"Exception value: {exc_value}")
print(f"Traceback: {traceback}")
# 返回 True 表示异常已处理,不再传播;返回 False 表示异常未处理,继续传播
return False
if __name__ == '__main__':
with FileManager('text.txt', 'a') as file:
for i in range(10):
file.write(f'{i}\n')
使用@contextmanager
装饰器
Python提供了contextlib.contextmanager
装饰器允许你使用生成器函数编写上下文管理器,简化了定义过程。生成器函数的 yield 语句分隔了 enter 和 exit 方法的代码。
from contextlib import contextmanager
@contextmanager
def file_manager(filename,mode):
file = open(filename,mode,encoding='utf-8')
try:
yield file
finally:
file.close()
with file_manager('乐都节水.txt', 'a') as file:
for i in range(10):
file.write(f'{i}\n')
在这个示例中,加入了yield
关键字,在yield之前,相当于__enter__
,yield之后相当于__exit__
,使用contextmanager装饰器,实现with上下文管理器更为简单
上下文管理器的实际应用
除了文件操作和性能测量,上下文管理器还有许多实际应用,例如:
- 数据库连接:确保数据库连接在使用后关闭。
- 线程锁:确保线程锁在使用后释放。
- 临时文件:确保临时文件在使用后删除。
下面展示一个数据库连接示例,在我们使用sqlite3时,如果连接没有即时释放,很容易造成后面的操作无法执行的问题,
from contextlib import contextmanager
import sqlite3
@contextmanager
def database_connection(db_name):
conn = sqlite3.connect(db_name)
try:
yield conn
finally:
conn.close()
# 使用 @contextmanager 装饰器管理数据库连接
with database_connection('data.db') as conn:
cursor = conn.cursor()
cursor.execute('SELECT * FROM RealData')
for row in cursor.fetchall():
print(row)
上面代码中,database_connection 生成器方式在yield前打开数据库连接,并在之后关闭连接,确保数据库连接在使用后自动释放
结论
使用 with
语句和上下文管理器可以大大简化资源管理,确保资源在使用后自动释放,减少错误和资源泄漏的风险。通过编写自定义上下文管理器或使用 @contextmanager 装饰器,你可以将常见的资源管理任务封装起来,使代码更加简洁和易于维护。
上下文管理器不仅限于文件操作和数据库连接,还可以应用于各种需要在使用后进行清理的资源管理任务。理解和使用上下文管理器是提升 Python 编程技能的重要一步。