with ... as ...、zip
2026/8/21 11:38:40 网站建设 项目流程

一、with ... as ...是固定配套语法,缺一不可

with 后面必须接一个上下文管理器,这个管理器包含(__enter__ / __exit__)
with 语法的底层机制完全依赖enter+exit;只要对象实现这两个方法,就能作为 with 的参数。Session() 和 .begin() 只是返回了两种逻辑不同的管理器实例。

with是上下文管理器关键字,as用来接收上下文返回的对象,标准写法一定成对出现,少数极简写法可以省略as(不需要拿到对象时):

# 有as:拿到session对象(你代码里的场景)withSessionLocal.begin()assession:session.add(...)# 无as:只需要自动释放资源,不用操作对象withopen("a.txt"):print("文件自动打开关闭")

二、核心作用:自动管理资源,自动清理(不用手动写try-finally)

with底层依赖上下文管理器协议__enter__/__exit__),进入代码块自动执行__enter__,退出时无论是否报错都会执行__exit__释放资源。

常见使用场景(全部是需要「用完必须关闭/回滚/释放」的资源)

1. 数据库连接/会话(你写的SQLAlchemy场景)

# SessionLocal.begin() 返回事务上下文withSessionLocal.begin()assession:session.add(user)# 代码块正常走完:自动commit提交事务# 代码块抛异常:自动rollback回滚事务# 离开块自动关闭session,不用手动 session.close()

不用with的原生写法,必须手动处理异常、提交、关闭,非常啰嗦:

session=SessionLocal()try:session.begin()session.add(user)session.commit()exceptException:session.rollback()finally:session.close()

2. 文件读写(最经典例子)

自动关闭文件,避免文件句柄泄露:

withopen("test.txt","r",encoding="utf-8")asf:data=f.read()# 离开with自动f.close()

3. 网络连接:socket、requests会话、数据库游标

importpsycopg2withpsycopg2.connect(...)asconn:withconn.cursor()ascur:cur.execute("SELECT 1")# 自动关闭游标、断开连接

4. 锁、线程同步资源(threading.Lock)

自动加锁、释放锁,防止死锁:

importthreading lock=threading.Lock()withlock:# 自动acquire加锁print("临界区代码")# 离开自动release解锁

5. 临时修改环境、恢复状态

比如临时改日志级别、临时切换目录,退出自动还原:

importoswithos.chdir("/tmp"):print(os.getcwd())# 自动切回原来工作目录

6. 自定义上下文管理器

自己实现__enter__/__exit__或者用@contextmanager装饰器封装资源逻辑。

三、with SessionLocal.begin() as session

SQLAlchemy 的begin()是事务上下文管理器:

  1. 进入with:开启数据库事务
  2. 块内正常执行完毕:自动commit
  3. 块内任意代码抛出异常:自动rollback
  4. 块结束:自动关闭会话,释放数据库连接回连接池

如果不用with,一旦中间代码报错忘记写rollback()/close(),会导致连接泄漏、事务卡死。

四、补充区分:两种with写法

  1. 需要操作对象 →with xxx as obj:(90%场景,你代码属于这种)
  2. 只需要自动释放、不用操作对象 →with xxx:(极少用)

五、一句话总结

  1. withas是配套语法,绝大多数场景都要一起写;
  2. 只要资源必须手动关闭/回滚/释放,就优先用with as
  3. 核心优势:自动清理资源、异常安全,替代冗长的try...finally

zip

核心本质:zip迭代时产出元组

1. 基础行为

zip(*iterables)会并行遍历所有传入可迭代对象,按位置配对,每一组打包成 tuple

a=[1,2,3]b=["x","y","z"]res=zip(a,b)foriteminres:print(item)# (1, 'x')# (2, 'y')# (3, 'z')# item 全部是元组 tuple

2. 关键特性补充

  1. 长度以最短序列为准
    多余元素直接丢弃:
zip([1,2],["a","b","c"])# 只生成2个元组
  1. 返回的不是列表,是迭代器
    省内存,只在遍历的时候才生成元组,不是一次性全部建好:
print(zip([1,2],[3,4]))# <zip object at 0x...>list(zip(...))# 把所有元组收集成列表
  1. 传 N 个可迭代对象,元组长度就是 N
zip([1],[2],[3])# (1,2,3) 三元组

3. 反向操作:解压 zip

*解包把一组元组还原回原始序列:

pairs=[(1,"x"),(2,"y")]nums,chars=zip(*pairs)# nums = (1,2)# chars = ('x','y')

一句话总结

zip就是并行配对多个序列,逐个生成位置对应的元组,且是惰性迭代器。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询