Python 中的条件 with 语句

新手上路,请多包涵

有没有一种方法可以有条件地使用 with 语句开始一段代码?

就像是:

 if needs_with():
    with get_stuff() as gs:

# do nearly the same large block of stuff,
# involving gs or not, depending on needs_with()

澄清一下,一种情况是将一个块封装在 with 语句中,而另一种可能性是相同的块,但没有封装(即,就好像它没有缩进一样)

最初的实验当然会给出缩进错误..

原文由 norman 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 674
2 个回答

如果你想避免重复代码并且使用 3.7 之前的 Python 版本(引入 contextlib.nullcontext 时)甚至 3.3(引入 contextlib.ExitStack 时),你可以做类似的事情:

 class dummy_context_mgr():
    def __enter__(self):
        return None
    def __exit__(self, exc_type, exc_value, traceback):
        return False

或者:

 import contextlib

@contextlib.contextmanager
def dummy_context_mgr():
    yield None

然后将其用作:

 with get_stuff() if needs_with() else dummy_context_mgr() as gs:
   # do stuff involving gs or not

您也可以根据 get_stuff() 返回不同的东西 needs_with()

(请参阅 Mike 的回答Daniel 的回答,了解您可以在以后的版本中做什么。)

原文由 jamesdlin 发布,翻译遵循 CC BY-SA 4.0 许可协议

Python 3.3 及以上版本

Python 3.3 引入了 contextlib.ExitStack 正是针对这种情况。它为您提供了一个“堆栈”,您可以根据需要向其中添加上下文管理器。在你的情况下,你会这样做:

 from contextlib import ExitStack

with ExitStack() as stack:
    if needs_with():
        gs = stack.enter_context(get_stuff())

    # do nearly the same large block of stuff,
    # involving gs or not, depending on needs_with()

输入到 stack 的任何内容都会像往常一样自动 exitwith 语句的末尾编辑。 (如果未输入任何内容,那不是问题。)在本示例中,无论 get_stuff() 返回什么,都是 exit 自动编辑。

如果您必须使用较早版本的 python,则可以使用 contextlib2 模块,尽管这不是标准的。它将此功能和其他功能反向移植到早期版本的 python。如果您喜欢这种方法,您甚至可以进行条件导入。


Python 3.7 及以上版本

Python 3.7 进一步引入了 contextlib.nullcontext (这个答案最初发布几年后,从那时起在其他几个答案中提到)。在评论中,@Kache 指出了这个选项最优雅的用法:

 from contextlib import nullcontext

with get_stuff() if needs_with() else nullcontext() as gs:
    # do nearly the same large block of stuff,
    # involving gs or not, depending on needs_with()

请注意,如果 needs_with() gs False None 如果您想要 gs nullcontext(something_else) -be something_else 在这种情况下,您只需替换 nullcontext()

这种方法显然不如 ExitStack 灵活,因为这只是一个二元选择,而 ExitStack 允许您添加尽可能多的 exit ,逻辑复杂等等。但这肯定满足了 OP 的简单要求。

原文由 Mike 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题