使用with
Python中的语句可以声明多个变量吗?
就像是:
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)
...还是同时清理两个资源是问题吗?
使用with
Python中的语句可以声明多个变量吗?
就像是:
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)
...还是同时清理两个资源是问题吗?
Answers:
从v3.1和 Python 2.7 开始,在Python 3中是可能的。新with
语法支持多个上下文管理器:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
不同于contextlib.nested
,这保证了即使或方法引发异常,a
也b
将__exit__()
调用C()
的__enter__()
。
您也可以在较新的定义中使用较早的变量(以下为h / t Ahmad):
with A() as a, B(a) as b, C(a, b) as c:
doSomething(a, c)
with open('./file') as arg.x = file:
?
as
是可选的。
as
如果你需要的对象是必需的a
或b
,但整体as a
还是as b
不需要
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的答案。
nested
上下文管理器是一个错误,永远不要使用。在此示例中,如果打开第二个文件引发异常,则第一个文件将完全不会关闭,从而完全破坏了使用上下文管理器的目的。
with
块。在进入with块之前按顺序创建管理器:m1,m2,m3 = A(),B(),C()如果B()或C()异常失败,那么您唯一希望正确完成A( )是垃圾收集器。
请注意,如果将变量分成几行,则必须使用反斜杠来包装换行符。
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:语法无效
https://bugs.python.org/issue12782似乎与此问题有关。
我认为您想这样做:
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)
因为Python 3.3,你可以使用类ExitStack
从contextlib
模块。
它可以管理动态数量的上下文感知对象,这意味着如果您不知道要处理多少文件,它将证明特别有用。
文档中提到的规范用例正在管理动态文件数量。
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
这也意味着您可以在第二个表达式中使用第一个表达式的别名(在使用数据库连接/游标时很有用):
with get_conn() as conn, conn.cursor() as cursor:
cursor.execute(sql)