是否可以在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)
... 还是同时清理两个资源才是问题所在?
是否可以在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)
... 还是同时清理两个资源才是问题所在?
当前回答
从Python 3.3开始,你可以使用contextlib模块中的ExitStack类。
它可以管理动态数量的上下文感知对象,这意味着如果您不知道要处理多少文件,它将特别有用。
文档中提到的规范用例是管理动态数量的文件。
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# All opened files will automatically be closed at the end of
# the with statement, even if attempts to open files later
# in the list raise an exception
下面是一个通用的例子:
from contextlib import ExitStack
class X:
num = 1
def __init__(self):
self.num = X.num
X.num += 1
def __repr__(self):
cls = type(self)
return '{cls.__name__}{self.num}'.format(cls=cls, self=self)
def __enter__(self):
print('enter {!r}'.format(self))
return self.num
def __exit__(self, exc_type, exc_value, traceback):
print('exit {!r}'.format(self))
return True
xs = [X() for _ in range(3)]
with ExitStack() as stack:
print(stack._exit_callbacks)
nums = [stack.enter_context(x) for x in xs]
print(stack._exit_callbacks)
print(stack._exit_callbacks)
print(nums)
输出:
deque([])
enter X1
enter X2
enter X3
deque([<function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86158>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f861e0>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86268>])
exit X3
exit X2
exit X1
deque([])
[1, 2, 3]
其他回答
这在Python 3 v3.1和Python 2.7中是可能的。新的with语法支持多个上下文管理器:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
不像contextlib。嵌套的,这保证了a和b的__exit__()将被调用,即使C()或它的__enter__()方法引发异常。
你也可以在后面的定义中使用之前的变量(下面是h/t 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)
从Python 3.3开始,你可以使用contextlib模块中的ExitStack类。
它可以管理动态数量的上下文感知对象,这意味着如果您不知道要处理多少文件,它将特别有用。
文档中提到的规范用例是管理动态数量的文件。
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# All opened files will automatically be closed at the end of
# the with statement, even if attempts to open files later
# in the list raise an exception
下面是一个通用的例子:
from contextlib import ExitStack
class X:
num = 1
def __init__(self):
self.num = X.num
X.num += 1
def __repr__(self):
cls = type(self)
return '{cls.__name__}{self.num}'.format(cls=cls, self=self)
def __enter__(self):
print('enter {!r}'.format(self))
return self.num
def __exit__(self, exc_type, exc_value, traceback):
print('exit {!r}'.format(self))
return True
xs = [X() for _ in range(3)]
with ExitStack() as stack:
print(stack._exit_callbacks)
nums = [stack.enter_context(x) for x in xs]
print(stack._exit_callbacks)
print(stack._exit_callbacks)
print(nums)
输出:
deque([])
enter X1
enter X2
enter X3
deque([<function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86158>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f861e0>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86268>])
exit X3
exit X2
exit X1
deque([])
[1, 2, 3]
在Python 3.1+中,你可以指定多个上下文表达式,它们将被处理,就像多个with语句嵌套一样:
with A() as a, B() as b:
suite
等于
with A() as a:
with B() as b:
suite
这也意味着你可以在第二个表达式中使用第一个表达式的别名(在使用db连接/游标时很有用):
with get_conn() as conn, conn.cursor() as cursor:
cursor.execute(sql)
我认为你应该这样做:
from __future__ import with_statement
with open("out.txt","wt") as file_out:
with open("in.txt") as file_in:
for line in file_in:
file_out.write(line)
contextlib。Nested支持:
import contextlib
with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):
...
更新: 引用文档,关于contextlib.nested:
2.7版后已移除:with-statement现在支持此功能 直接使用功能(没有容易出错的令人困惑的怪癖)。
更多信息请参见rafawarsaw Dowgird的回答。