在python中创建多行with
的简洁方法是什么?我想在单个with
内打开几个文件,但它在我想要它的多行上足够远。像这样:
class Dummy:
def __enter__(self): pass
def __exit__(self, type, value, traceback): pass
with Dummy() as a, Dummy() as b,
Dummy() as c:
pass
不幸的是,那是SyntaxError
。所以我尝试了这个:
with (Dummy() as a, Dummy() as b,
Dummy() as c):
pass
也是语法错误。但是,这有效:
with Dummy() as a, Dummy() as b,\
Dummy() as c:
pass
但是,如果我想发表评论怎么办?这不起作用:
with Dummy() as a, Dummy() as b,\
# my comment explaining why I wanted Dummy() as c\
Dummy() as c:
pass
\
的位置也没有任何明显的变化。
是否有一种干净的方法来创建允许在其中发表评论的多行with
语句?
答案 0 :(得分:37)
鉴于您已标记此Python 3,如果您需要在上下文管理器中散布注释,我会使用contextlib.ExitStack
:
with ExitStack() as stack:
a = stack.enter_context(Dummy()) # Relevant comment
b = stack.enter_context(Dummy()) # Comment about b
c = stack.enter_context(Dummy()) # Further information
这相当于
with Dummy() as a, Dummy() as b, Dummy() as c:
这样做的好处是,您可以在循环中生成上下文管理器,而不需要单独列出每个上下文管理器。文档给出了一个示例,如果要打开一堆文件,并且列表中有文件名,则可以执行
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
如果您的上下文管理器占用了大量屏幕空间,您希望在它们之间添加注释,那么您可能有足够的想要使用某种循环。
正如Deathless先生在评论中提到的那样,在名称contextlib2
下的PyPI上有一个contextlib backport。如果您使用的是Python 2,则可以使用backport的ExitStack
实现。
答案 1 :(得分:13)
这对我来说似乎最整洁:
with open('firstfile', 'r') as (f1 # first
), open('secondfile', 'r') as (f2 # second
):
pass
答案 2 :(得分:2)
这并不完全干净,但你可以这样做:
with Dummy() as a, Dummy() as b, (
#my comment
Dummy()) as c:
pass
没有语法错误,但它不是最干净的。你也可以这样做:
with Dummy() as a, Dummy() as b, Dummy(
#my comment
) as c:
pass
考虑在不使用with
。
答案 3 :(得分:2)
我可以通过在with
语句之前或在行本身上添加注释来使事情简单易懂:
# my comment explaining why I wanted Dummy() as c
with Dummy() as a, Dummy() as b,\
Dummy() as c: # or add the comment here
pass
答案 4 :(得分:2)
此问题已在Python 3.9中修复!
https://github.com/we-like-parsers/pegen/issues/229
with (Dummy() as a,
Dummy() as b,
# my comment explaining why I wanted Dummy() as c
Dummy() as c):
pass
这里证明它有效:
Python 3.9.0a6 (default, Jun 20 2020, 14:52:53)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.15.0 -- An enhanced Interactive Python. Type '?' for help.
In [3]: with (open('x')
...: as f):
...: pass
...:
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-3-47d5a51db08b> in <module>
----> 1 with (open('x')
2 as f):
3 pass
4
FileNotFoundError: [Errno 2] No such file or directory: 'x'
In [4]:
Do you really want to exit ([y]/n)? y
wPython 3.8.2 (default, May 8 2020, 20:08:31)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.15.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: with (open('x')
...: as f):
...: pass
File "<ipython-input-1-e538abd13934>", line 2
as f):
^
SyntaxError: invalid syntax
答案 5 :(得分:0)
类似于TigerhawkT3's answer,但缩进不会触发pycodestyle's error E124:
with (
open('firstfile', 'r')) as f1, ( # first
open('secondfile', 'r')) as f2: # second
pass
IMO仍然很丑陋,但至少它通过了短绒。