with'语句中的多个变量?
在Python中,使用with
语句可以同时声明多个变量吗?
像这样:
from __future__ import with_statement
with open("out.txt","wt"), open("in.txt") as file_out, file_in:
for line in file_in:
file_out.write(line)
...或者说,同时处理两个资源会有问题吗?
8 个回答
contextlib.nested
这个东西可以支持这样的用法:
import contextlib
with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):
...
更新:
根据文档的说法,关于 contextlib.nested
:
自2.7版本起已不再推荐使用:现在的with语句直接支持这个功能(而且没有那些让人困惑且容易出错的怪癖)。
想了解更多信息,可以查看 Rafał Dowgird的回答。
注意,如果你在Python 3.10之前把变量分成多行,你必须用反斜杠来连接这些换行。
with A() as a, \
B() as b, \
C() as c:
doSomething(a,b,c)
用括号是行不通的,因为Python会把它当成一个元组。
with (A(),
B(),
C()):
doSomething(a,b,c)
由于元组没有__enter__
这个属性,所以你会遇到一个错误(这个错误信息不太清楚,也不能告诉你是哪种类的问题):
AttributeError: __enter__
如果你在括号里尝试使用as
,Python会在解析时就抓住这个错误:
with (A() as a,
B() as b,
C() as c):
doSomething(a,b,c)
SyntaxError: invalid syntax
这个问题什么时候会解决?
这个问题正在跟踪中,具体可以查看 https://bugs.python.org/issue12782。
Python在 PEP 617 中宣布,他们会用一个新的解析器来替代原来的解析器。因为Python的原解析器是LL(1)类型的,它 无法区分 “多个上下文管理器” with (A(), B()):
和 “值的元组” with (A(), B())[0]:
。
新的解析器可以正确解析被括号包围的多个上下文管理器。这个新解析器在3.9版本中已经启用。有人报告说,直到Python 3.10移除旧解析器之前,这种语法仍然会被拒绝,而这个语法的变化在 3.10版本更新说明中有提到。不过在我的测试中,它在trinket.io的Python 3.9.6中也是可以正常工作的。
在Python 3.1版本及以上和Python 2.7中,可以使用一种新的写法。这个新的with
语法支持同时管理多个上下文。
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
跟之前的contextlib.nested
不同,这种写法保证了即使在执行C()
或者它的__enter__()
方法时出现了错误,a
和b
的__exit__()
方法也会被调用。
你还可以在后面的定义中使用之前定义的变量(感谢下面的Ahmad):
with A() as a, B(a) as b, C(a, b) as c:
doSomething(a, c)
从Python 3.10开始,你可以使用括号来写这些上下文管理器:
with (
A() as a,
B(a) as b,
C(a, b) as c,
):
doSomething(a, c)