with ... as ...、zip

📅 2026/8/21 11:38:48
with ... as ...、zip
一、with ... as ...是固定配套语法缺一不可with 后面必须接一个上下文管理器,这个管理器包含__enter__ / __exit__with 语法的底层机制完全依赖enterexit只要对象实现这两个方法就能作为 with 的参数。Session() 和 .begin() 只是返回了两种逻辑不同的管理器实例。with是上下文管理器关键字as用来接收上下文返回的对象标准写法一定成对出现少数极简写法可以省略as不需要拿到对象时# 有as拿到session对象你代码里的场景withSessionLocal.begin()assession:session.add(...)# 无as只需要自动释放资源不用操作对象withopen(a.txt):print(文件自动打开关闭)二、核心作用自动管理资源自动清理不用手动写try-finallywith底层依赖上下文管理器协议__enter__/__exit__进入代码块自动执行__enter__退出时无论是否报错都会执行__exit__释放资源。常见使用场景全部是需要「用完必须关闭/回滚/释放」的资源1. 数据库连接/会话你写的SQLAlchemy场景# SessionLocal.begin() 返回事务上下文withSessionLocal.begin()assession:session.add(user)# 代码块正常走完自动commit提交事务# 代码块抛异常自动rollback回滚事务# 离开块自动关闭session不用手动 session.close()不用with的原生写法必须手动处理异常、提交、关闭非常啰嗦sessionSessionLocal()try:session.begin()session.add(user)session.commit()exceptException:session.rollback()finally:session.close()2. 文件读写最经典例子自动关闭文件避免文件句柄泄露withopen(test.txt,r,encodingutf-8)asf:dataf.read()# 离开with自动f.close()3. 网络连接socket、requests会话、数据库游标importpsycopg2withpsycopg2.connect(...)asconn:withconn.cursor()ascur:cur.execute(SELECT 1)# 自动关闭游标、断开连接4. 锁、线程同步资源threading.Lock自动加锁、释放锁防止死锁importthreading lockthreading.Lock()withlock:# 自动acquire加锁print(临界区代码)# 离开自动release解锁5. 临时修改环境、恢复状态比如临时改日志级别、临时切换目录退出自动还原importoswithos.chdir(/tmp):print(os.getcwd())# 自动切回原来工作目录6. 自定义上下文管理器自己实现__enter__/__exit__或者用contextmanager装饰器封装资源逻辑。三、with SessionLocal.begin() as sessionSQLAlchemy 的begin()是事务上下文管理器进入with开启数据库事务块内正常执行完毕自动commit块内任意代码抛出异常自动rollback块结束自动关闭会话释放数据库连接回连接池如果不用with一旦中间代码报错忘记写rollback()/close()会导致连接泄漏、事务卡死。四、补充区分两种with写法需要操作对象 →with xxx as obj:90%场景你代码属于这种只需要自动释放、不用操作对象 →with xxx:极少用五、一句话总结with和as是配套语法绝大多数场景都要一起写只要资源必须手动关闭/回滚/释放就优先用with as核心优势自动清理资源、异常安全替代冗长的try...finally。zip核心本质zip迭代时产出元组1. 基础行为zip(*iterables)会并行遍历所有传入可迭代对象按位置配对每一组打包成 tuplea[1,2,3]b[x,y,z]reszip(a,b)foriteminres:print(item)# (1, x)# (2, y)# (3, z)# item 全部是元组 tuple2. 关键特性补充长度以最短序列为准多余元素直接丢弃zip([1,2],[a,b,c])# 只生成2个元组返回的不是列表是迭代器省内存只在遍历的时候才生成元组不是一次性全部建好print(zip([1,2],[3,4]))# zip object at 0x...list(zip(...))# 把所有元组收集成列表传 N 个可迭代对象元组长度就是 Nzip([1],[2],[3])# (1,2,3) 三元组3. 反向操作解压 zip*解包把一组元组还原回原始序列pairs[(1,x),(2,y)]nums,charszip(*pairs)# nums (1,2)# chars (x,y)一句话总结zip就是并行配对多个序列逐个生成位置对应的元组且是惰性迭代器。