将Python上下文管理器的迭代器嵌套在“with”中

编程入门 行业动态 更新时间:2024-10-24 07:26:01
本文介绍了将Python上下文管理器的迭代器嵌套在“with”中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有一个返回上下文管理器的迭代器。

I have an iterator that returns context managers.

我想要一个带有语句的pythonic 语句,它模拟了几个嵌套的带有语句的行为,迭代器返回的每个上下文管理器都有一个。

I want a pythonic with statement, that emulates the behaviour of several nested with statements, one for each context manager returned by the iterator.

可以说,我想要推广(已弃用) contextlib.nested 函数。

One could say, I want a generalisation of the (deprecated) contextlib.nested function.

推荐答案

contextlib.nested 有两个主要问题导致它被弃用。

contextlib.nested has two major problems that caused it to be deprecated.

  • 第一个问题是内部上下文管理器可能会在 __ init __ 或 __ new __ 期间引发异常,这些异常会导致整个with语句在不调用外部管理器的 __ exit __ 的情况下中止。
  • 第二个问题更复杂。如果其中一个内部经理引发异常而其中一个外部经理通过在 __ exit __ 中返回 True 来捕获它,块仍应执行。但是在嵌套的实现中,它只是在不执行块的情况下引发 RuntimeError 。此问题可能需要完全重写嵌套。
  • first problem is that inner context managers might raise Exceptions during __init__ or __new__, and these exceptions would cause the whole with statement to abort without calling __exit__ of the outer manager.
  • The second problem is more complicated. If one of the inner managers raises an exception and one of the outer managers catches it by returning True in __exit__, the block should still be executed. But in the implementation of nested, it just raises a RuntimeError without executing the block. This problem probably requires a total rewrite of nested.
  • 但这是可能的通过在嵌套的定义中删除一个 * 来解决第一个问题! 这改变了行为,使得嵌套不再接受参数列表(这无论如何都没用,因为带有已经可以处理了)但只有一个迭代器。因此,我将新版本称为 iter_nested 。 然后,用户可以定义迭代器,在迭代期间实例化上下文管理器。

    But it is possible to solve the first problem by just removing one * in the definition of nested! This changes the behaviour such that nested doesn't accept argument lists anymore (which isn't useful anyway because with can handle that already) but only an iterator. I therefore call the new version "iter_nested". The user can then define an iterator that instantiates the context managers during iteration.

    生成器的示例:

    def contexts(): yield MyContext1() yield MyContext2() with iter_nested(contexts()) as contexts: do_stuff(contexts[0]) do_other_stuff(contexts[1])

    原始代码与我更改的嵌套版本之间的差异在于:

    The difference between the codes of the original and my changed version of nested is here:

    from contextlib import contextmanager @contextmanager --- def nested(*managers): +++ def iter_nested(mgr_iterator): --- #comments & deprecation warning exits = [] vars = [] --- exc = (None, None, None) +++ exc = None # Python 3 try: --- for mgr in managers: +++ for mgr in mgr_iterator: exit = mgr.__exit__ enter = mgr.__enter__ vars.append(enter()) exits.append(exit) yield vars # All of the following is new and fit for Python 3 except Exception as exception: exc = exception exc_tuple = (type(exc), exc, exc.__traceback__) else: exc_tuple = (None, None, None) finally: while exits: exit = exits.pop() try: if exit(*exc_tuple): exc = None exc_tuple = (None, None, None) except Exception as exception: exception.__context__ = exc exc = exception exc_tuple = (type(exc), exc, exc.__traceback__) if exc: raise exc

    更多推荐

    将Python上下文管理器的迭代器嵌套在“with”中

    本文发布于:2023-11-23 10:09:45,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1621061.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:嵌套   上下文   管理器   迭代   Python

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!