“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)
...或者同时清理两个资源是问题所在?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
Python 3 自 v3.1 和 Python 2.7。 新的
with
语法支持多个上下文管理器:与
contextlib.nested
不同,这保证a
和b
将拥有其__exit__()C()
或其__enter__()
方法引发异常,> 也会被调用。您还可以在后面的定义中使用前面的变量 (h/t Ahmad下面):
从 Python 3.10 开始,您可以使用括号:
It is possible in Python 3 since v3.1 and Python 2.7. The new
with
syntax supports multiple context managers:Unlike the
contextlib.nested
, this guarantees thata
andb
will have their__exit__()
's called even ifC()
or it's__enter__()
method raises an exception.You can also use earlier variables in later definitions (h/t Ahmad below):
As of Python 3.10, you can use parentheses:
请注意,如果将变量拆分为行,则在 Python 3.10 之前,必须使用反斜杠来换行。
括号不起作用,因为 Python 创建了一个元组。
由于元组缺少
__enter__
属性,因此您会收到错误(非描述性且无法识别类类型):如果您尝试在括号内使用
as
,Python 将在解析时捕获错误:这个问题什么时候能修复?
此问题在 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。
Note that if you split the variables into lines, prior to Python 3.10 you must use backslashes to wrap the newlines.
Parentheses don't work, since Python creates a tuple instead.
Since tuples lack a
__enter__
attribute, you get an error (undescriptive and does not identify class type):If you try to use
as
within parentheses, Python catches the mistake at parse time:When will this be fixed?
This issue is tracked in https://bugs.python.org/issue12782.
Python announced in PEP 617 that they would replace the original parser with a new one. Because Python's original parser is LL(1), it cannot distinguish between "multiple context managers"
with (A(), B()):
and "tuple of values"with (A(), B())[0]:
.The new parser can properly parse multiple context managers surrounded by parentheses. The new parser has been enabled in 3.9. It was reported that this syntax will still be rejected until the old parser is removed in Python 3.10, and this syntax change was reported in the 3.10 release notes. But in my testing, it works in trinket.io's Python 3.9.6 as well.
contextlib.nested
支持此功能:更新:
引用文档,关于
contextlib.nested
< /a>:有关更多信息,请参阅Rafał Dowgird 的回答。
contextlib.nested
supports this:Update:
To quote the documentation, regarding
contextlib.nested
:See Rafał Dowgird's answer for more information.
从Python 3.3开始,您可以使用类
ExitStack
来自contextlib
模块。它可以管理动态数量的上下文感知对象,这意味着如果您不知道要处理多少个文件,它将特别有用。
文档中提到的规范用例是管理动态数量的文件。
这是一个通用示例:
输出:
Since Python 3.3, you can use the class
ExitStack
from thecontextlib
module.It can manage a dynamic number of context-aware objects, which means that it will prove especially useful if you don't know how many files you are going to handle.
The canonical use-case that is mentioned in the documentation is managing a dynamic number of files.
Here is a generic example:
Output:
我想你想这样做:
I think you want to do this instead:
从 Python 3.10 开始,有一个新功能 括号上下文管理器,它允许如下语法:
From Python 3.10 there is a new feature of Parenthesized context managers, which permits syntax such as:
在 Python 3.1+ 中,您可以指定多个上下文表达式,它们将被视为嵌套了多个
with
语句:相当于
这也意味着您可以在第二个表达式中使用第一个表达式中的别名(在使用数据库连接/游标时很有用):
In Python 3.1+ you can specify multiple context expressions, and they will be processed as if multiple
with
statements were nested:is equivalent to
This also means that you can use the alias from the first expression in the second (useful when working with db connections/cursors):
您还可以单独创建上下文管理器(
__init__
方法)并输入上下文(__init__
方法) >__enter__ 方法)以增加可读性。 编写以下代码,而不是编写因此,您可以
此代码:请注意,在
with
语句之外创建上下文管理器会让人觉得所创建的对象也可以在该语句之外进一步使用。 如果您的上下文管理器不是这样,则错误的印象可能会与可读性尝试相对应。文档说:
You can also separate creating a context manager (the
__init__
method) and entering the context (the__enter__
method) to increase readability. So instead of writing this code:you can write this code:
Note that creating the context manager outside of the
with
statement makes an impression that the created object can also be further used outside of the statement. If this is not true for your context manager, the false impression may counterpart the readability attempt.The documentation says: