是否可以在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)
......还是正在清理两个资源同时出现问题?
也许是这样的:将[expr1,expr2]作为f:然后使用f [0]和f [1]。
本来不错,因为不需要导入一些东西....但它不起作用AttributeError:'list'对象没有属性'exit'
如果python只有闭包,你就不需要with语句
你不需要使用with语句,对吗?您可以将file_out和file_in设置为None,然后执行try / except / finally打开它们并在try中处理它们,然后在最后关闭它们(如果它们不是None)。不需要双缩进。
其中许多答案都没有涉及超过两个语句的需要。从理论上讲,可能存在需要打开数十个上下文的应用程序,嵌套很快就会崩溃,因为任何行长度都会受到限制。
@Mark Amery。是的,但我先问:)
是否有可能将字段设置为与with open('./file') as arg.x = file:中的语句相同?
@ThorSummoner看到描述contextlib.ExitStack的答案。
从v3.1和Python 2.7开始,它可以在Python 3中实现。新的with语法支持多个上下文管理器:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
与contextlib.nested不同,这保证即使C()或__enter__()方法引发异常,a和b也会调用__exit__()。
是否可以在with open('./file') as arg.x = file:中将字段设置为与语句中的某些内容相同?
此外,有可能:A()为a,B(a)为b,C(a,b)为c:
class test2:x = 1; t2 = test2(),open('f2.txt')为t2.x:for t1.x.readlines()中的l1:print(l1); #Charlie Parker#在python 3.6中测试过
请注意,as是可选的。
contextlib.nested支持这个:
import contextlib
with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):
...
更新:
引用文档,关于contextlib.nested:
Deprecated since version 2.7: The with-statement now supports this
functionality directly (without the confusing error prone quirks).
看拉法? Dowgird的回答是为了获取更多信息。
我很遗憾地说,但我认为nested上下文管理器是一个错误,永远不应该使用。在此示例中,如果打开第二个文件引发异常,则第一个文件根本不会关闭,从而完全破坏了使用上下文管理器的目的。
你为什么这么说?文档说使用嵌套等同于嵌套'with'
@Rafal:瞥一眼手册似乎表明python正确地嵌套了with语句。真正的问题是,如果第二个文件在关闭时抛出异常。
@Unknown:这也是我的阅读 - 据我所知,File对象在关闭时不会引发异常
@James:不,docs.python.org/library/contextlib.html#contextlib.nested文档中的等效代码与标准嵌套with块不同。在输入with块之前按顺序创建管理器:m1,m2,m3 = A(),B(),C()如果B()或C()失败但有异常,那么你唯一希望正确完成A( )是垃圾收集器。
@Rafal:在很多情况下,立即关闭所有非特殊出口都是合适的。例如,它是一种捕捉return和continue的简洁方法。
自2.7版以来已弃用。注意:with语句现在直接支持此功能(没有容易出错的容易出错的怪癖)。
请注意,如果将变量拆分为行,则必须使用反斜杠来换行换行符。
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似乎与此问题有关。
我想你想这样做:
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的禅"),"扁平比嵌套好" - 这就是我们将contextlib.nested添加到标准库的原因。顺便说一句,3.1可能有一个新的语法"用A()作为a,B()作为b:"(补丁是,到目前为止没有关于它的BDFL声明),以获得更直接的支持(显然,库解决方案不是'被认为是完美的......但是避免不必要的嵌套绝对是核心Python开发人员共同的目标。
@Alex:非常正确,但我们还必须考虑"可读性计数"。
@Andrew:我认为一个级别的缩进更好地表达了程序的预期逻辑,即"原子地"创建两个变量,并在以后一起清理它们(我意识到这实际上并不是发生了什么)。认为例外问题是一个交易破坏者
从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([._exit_wrapper at 0x7f5c95f86158>, ._exit_wrapper at 0x7f5c95f861e0>, ._exit_wrapper at 0x7f5c95f86268>])
exit X3
exit X2
exit X1
deque([])
[1, 2, 3]