Python多行语句

时间:2015-06-24 23:49:35

标签: python python-3.x multiline with-statement

在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语句?

6 个答案:

答案 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仍然很丑陋,但至少它通过了短绒。