python3 异步 async with 用法

本文详细介绍了异步上下文管理器asyncwith的使用方法,包括其核心概念、实现方式及新语法特性。通过具体示例,如数据库事务管理和锁的使用,展示了asyncwith如何简化异步代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异步上下文管理器”async with”

异步上下文管理器指的是在enterexit方法处能够暂停执行的上下文管理器。

为了实现这样的功能,需要加入两个新的方法:__aenter__ 和__aexit__。这两个方法都要返回一个 awaitable类型的值。

异步上下文管理器的一种使用方法是:

class AsyncContextManager:
    async def __aenter__(self):
        await log('entering context')

    async def __aexit__(self, exc_type, exc, tb):
        await log('exiting context')

新语法

异步上下文管理器使用一种新的语法:

async with EXPR as VAR:
    BLOCK

这段代码在语义上等同于:

mgr = (EXPR)
aexit = type(mgr).__aexit__
aenter = type(mgr).__aenter__(mgr)
exc = True

VAR = await aenter
try:
    BLOCK
except:
    if not await aexit(mgr, *sys.exc_info()):
        raise
else:
    await aexit(mgr, None, None, None)

和常规的with表达式一样,可以在一个async with表达式中指定多个上下文管理器。

如果向async with表达式传入的上下文管理器中没有__aenter__ 和__aexit__方法,这将引起一个错误 。如果在async def函数外面使用async with,将引起一个SyntaxError(语法错误)。

例子

使用async with能够很容易地实现一个数据库事务管理器。

async def commit(session, data):
    ...

    async with session.transaction():
        ...
        await session.update(data)
        ...

需要使用锁的代码也很简单:

async with lock:
    ...

而不是:

with (yield from lock):
    ...

 

 

### Python `with` 语句的使用方法 #### 基本概念 在 Python 编程中,`with...as` 是一种强大的功能,专门用于管理资源,例如文件、网络连接以及数据库连接等。它能够自动处理资源的分配和释放,从而减少手动干预带来的错误风险[^2]。 #### 工作原理 当执行到 `with` 语句时,会调用上下文管理器中的 `__enter__()` 方法来初始化对象并返回该对象给变量(如果存在 `as var_name`)。随后,在代码块结束时,无论是否发生异常都会触发 `__exit__()` 方法以清理资源。这种机制确保即使程序抛出异常也能安全关闭已打开的对象或断开链接[^3]。 #### 实际应用案例分析 以下是几个典型的例子展示如何利用此结构简化操作流程: ##### 文件读写操作 ```python # 正确方式:使用 with 打开文件 with open('example.txt', mode='r') as file: content = file.read() print(content) # 错误示范:不推荐的方式因为需要显式close()函数 file = open('example.txt', 'r') try: data = file.read() finally: file.close() ``` 上述第一个片段展示了通过引入 `with` 来替代传统 try-finally 结构的优势所在——不仅更加简洁明了而且不易遗漏任何细节步骤。 ##### 数据库事务控制 假设我们正在开发一个应用程序需要用到 SQLite 数据库存储数据,则可以这样实现原子性的提交或者回滚更改动作: ```python import sqlite3 connection_string = ":memory:" query_create_table = """ CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL); """ insert_user_query = """INSERT INTO users (name) VALUES (?);""" def create_database(): connection = None try: connection = sqlite3.connect(connection_string) cursor = connection.cursor() # 创建表单 cursor.execute(query_create_table) # 插入新记录 user_names = ["Alice", "Bob"] for name in user_names: cursor.execute(insert_user_query, (name,)) # 提交所有变更 connection.commit() except Exception as e: print(f"An error occurred while creating the database: {e}") if connection is not None: connection.rollback() finally: if connection is not None: connection.close() create_database() ``` 然而借助于 `contextlib.closing()` 或者直接继承自 BaseContextManager 类型的新类实例化之后再配合上 `with` 关键字则可以让整个过程变得更加流畅自然: ```python from contextlib import closing import sqlite3 class DatabaseConnection: def __init__(self, db_path): self.db_path = db_path def __enter__(self): self.conn = sqlite3.connect(self.db_path) return self.conn def __exit__(self,*args,**kwargs): self.conn.close() db_conn_str = ':memory:' queries_to_execute=["""CREATE TABLE test(id int primary key,name varchar(50))""", """INSERT INTO test values(1,'John Doe');"""] with DatabaseConnection(db_conn_str) as conn: cur=conn.cursor() for q in queries_to_execute :cur.executescript(q) result_set=[row for row in cur.fetchall()] print(result_set) ``` 这里定义了一个简单的上下文管理者 `DatabaseConnection`, 它封装了创建连接与销毁的过程;因此当我们进入 `with` 阻塞区的时候就会自动建立一个新的 SQL 连接,并且离开这个区域之前一定会将其妥善地予以终止. #### 注意事项 尽管 `assert` 表达式的初衷是用来调试期间验证某些前提条件成立与否,但在生产环境中应谨慎启用优化编译选项(-O),因为它可能会移除这些断言语句导致潜在隐患被忽略掉[^4].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值