我理解why contextlib.nested is deprecated。
但是如果我为一个旧的python版本编写一个程序,而不是多种形式的(例如,< 2.7),我(几乎)别无选择。
为了避免以下构造失败:
with nested(open("f1"), open("f2")) as (f1, f2):
(如果打开f1
失败,则f2
将无法关闭,因为未输入上下文管理器
我可以想象编写一个上下文管理器,将初始化移动到__enter__
:
@contextmanager
def late_init(f, *a, **k):
r = f(*a, **k)
with r as c: yield c
我是否正确地想到
with nested(late_init(open, "f1"), late_init(open, "f2")) as (f1, f2):
这足以让它“干净”吗?
给出的用例只是一个例子。想象一下,你有一个文件列表,其长度不是过早知道的。那么2.7组合的with
既不可用也不是2.7之前的嵌套方式,只有几个缩进的with
语句。
我可能必须对此更加冗长。
上述问题乍看之下解决了问题:调用函数在安全的地方执行,以便可以检测到失败并妥善处理。
我的问题是:它是否治愈了这个缺陷,还是我遇到了其他问题?
答案 0 :(得分:3)
contextlib.nested 工具用于将上下文管理器组合成一个。它被弃用了,因为它在设计上存在缺陷(正如你已经展示了如果打开 f2 失败则 f1 不会被关闭的情况)。
您使用案例虽然不需要合成。定期嵌套就足够了:
with open('f1') as f1:
with open('f2') as f2:
...
答案 1 :(得分:1)
我现在看到我的解决方案(late_init()
)可能会治愈第一个怪癖:
首先,因为上下文管理器都是在之前构建的 函数被调用,内部的
__new__()
和__init__()
方法 上下文管理器实际上并未涵盖外部的范围 情境管理者。这意味着,例如,使用nested()
打开 两个文件是编程错误,因为第一个文件不会被关闭 及时打开第二个文件时是否抛出异常。
但第二个:
其次,如果是
__enter__()
方法之一的内部上下文 管理者提出了一个由被抓住和压制的例外 其中一个外部上下文管理器的__exit__()
方法,此构造将引发RuntimeError而不是跳过with的主体 言。
(这可能是由yield vars
中跳过的nested()
引起的)不在其中。
所以要么
nested()
结合使用,nested()
应替换为更好的或