Python 多行 with 语句
Python multi-line 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
语句?
这不是很干净,但你可以这样做:
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
中间注释的方法。
这对我来说似乎最整洁:
with open('firstfile', 'r') as (f1 # first
), open('secondfile', 'r') as (f2 # second
):
pass
As of Python 3.10,现在可以用括号括起整个上下文管理器组,正如您最初尝试的那样:
with (Dummy() as a, Dummy() as b,
# comment about c
Dummy() as c):
pass
这在 3.9 中在技术上也是可行的,但在某种半文档化的边缘。
一方面,它在 3.10 中被记录为新的,3.9 不应该 引入依赖于 new parser implementation, and the 3.9 with
docs forbid this form. On the other hand, the functionality ended up getting activated in the 3.9 CPython implementation, and the (mostly?) auto-generated 3.9 full grammar spec 的任何功能(像这个)包括括号形式。
在以前的 Python 3 版本中,如果您需要在上下文管理器中穿插注释,我会使用 contextlib.ExitStack
:
from contextlib import 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]
如果您的上下文管理器占据了太多屏幕 space 以至于您想在它们之间放置注释,您可能有足够的空间想要使用某种循环。
正如 Deathless 先生在评论中提到的,PyPI 上有一个名为 contextlib2
的 contextlib backport。如果您使用的是 Python 2,则可以使用 ExitStack
.
的后向移植实现
顺便说一句,你不能做类似的事情的原因
with (
ThingA() as a,
ThingB() as b):
...
在新的解析器实现之前是因为 (
也可以是上下文管理器表达式的第一个标记,而 CPython 的旧解析器无法分辨当它看到第一个 (
时应该解析什么规则。这是 PEP 617 新的基于 PEG 的解析器的激励示例之一。
喜欢, but with indenting that doesn't trigger pycodestyle's error E124:
with (
open('firstfile', 'r')) as f1, ( # first
open('secondfile', 'r')) as f2: # second
pass
IMO 它仍然很难看,但至少它通过了 linter。
我会通过在 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
Python 仅限 3.9+:
with (
Dummy() as a,
Dummy() as b,
# my comment explaining why I wanted Dummy() as c
Dummy() as c,
):
pass
Python≤3.8:
with \
Dummy() as a, \
Dummy() as b, \
Dummy() as c:
pass
遗憾的是,无法使用此语法进行注释。
在 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
语句?
这不是很干净,但你可以这样做:
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
中间注释的方法。
这对我来说似乎最整洁:
with open('firstfile', 'r') as (f1 # first
), open('secondfile', 'r') as (f2 # second
):
pass
As of Python 3.10,现在可以用括号括起整个上下文管理器组,正如您最初尝试的那样:
with (Dummy() as a, Dummy() as b,
# comment about c
Dummy() as c):
pass
这在 3.9 中在技术上也是可行的,但在某种半文档化的边缘。
一方面,它在 3.10 中被记录为新的,3.9 不应该 引入依赖于 new parser implementation, and the 3.9 with
docs forbid this form. On the other hand, the functionality ended up getting activated in the 3.9 CPython implementation, and the (mostly?) auto-generated 3.9 full grammar spec 的任何功能(像这个)包括括号形式。
在以前的 Python 3 版本中,如果您需要在上下文管理器中穿插注释,我会使用 contextlib.ExitStack
:
from contextlib import 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]
如果您的上下文管理器占据了太多屏幕 space 以至于您想在它们之间放置注释,您可能有足够的空间想要使用某种循环。
正如 Deathless 先生在评论中提到的,PyPI 上有一个名为 contextlib2
的 contextlib backport。如果您使用的是 Python 2,则可以使用 ExitStack
.
顺便说一句,你不能做类似的事情的原因
with (
ThingA() as a,
ThingB() as b):
...
在新的解析器实现之前是因为 (
也可以是上下文管理器表达式的第一个标记,而 CPython 的旧解析器无法分辨当它看到第一个 (
时应该解析什么规则。这是 PEP 617 新的基于 PEG 的解析器的激励示例之一。
喜欢
with (
open('firstfile', 'r')) as f1, ( # first
open('secondfile', 'r')) as f2: # second
pass
IMO 它仍然很难看,但至少它通过了 linter。
我会通过在 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
Python 仅限 3.9+:
with (
Dummy() as a,
Dummy() as b,
# my comment explaining why I wanted Dummy() as c
Dummy() as c,
):
pass
Python≤3.8:
with \
Dummy() as a, \
Dummy() as b, \
Dummy() as c:
pass
遗憾的是,无法使用此语法进行注释。