2

我一直在使用很多上下文管理器作为组合各种设置/拆卸情况的干净方式。由于我的部署以 Python 2.6 为目标,这意味着使用contextlib.nested.

最近,我对使用相同的代码库同时支持 Python 2.x 和 Python 3 很感兴趣。这在某些项目中是可能的,但在上下文管理器的情况下我遇到了麻烦,因为:

  1. contextlib.nestedPython 3 不支持
  2. with aa() as a, bb() as b: ...2.6 不支持 Python-3 样式的嵌套上下文管理器(例如)。

这里有一个基本的语法不兼容。由于我无法控制的各种原因,2.7 目前可能难以投入生产,但我想尽可能地对代码进行未来验证,因此对 Python 3 很感兴趣。

任何人都可以建议一种解决方法来支持 2.6 和 3.x 的同一代码库中的嵌套上下文管理器吗?或者这是一个失败的原因?

4

4 回答 4

3

只是嵌套它们

with aa() as a:
    with bb() as b:
        #some code here
于 2013-10-01T21:24:34.043 回答
3

从文档:

这个函数有两个主要的怪癖导致它被弃用。首先,由于上下文管理器都是在函数被调用之前构建的,因此内部上下文管理器的__new__()__init__()方法实际上并没有被外部上下文管理器的范围覆盖。这意味着,例如,使用nested()打开两个文件是一个编程错误,因为如果在打开第二个文件时抛出异常,第一个文件将不会立即关闭。

其次,如果__enter__()内部上下文管理器之一的方法引发异常,该异常被__exit__()外部上下文管理器之一的方法捕获和抑制,则此构造将引发RuntimeError而不是跳过 with 语句的主体。

因此,几乎在所有情况下,正确答案都是 JBernardo 的。它的缩进有点多,但错误也少了一点。

于 2013-10-01T21:28:23.570 回答
2

如果nested提到的 Veedrac 的怪癖对您来说不是问题,您可以从 Python 标准库中复制代码。

如果它们确实困扰您,那么您唯一的选择是手动嵌套它们,或者放弃对 Python 2.6 的支持。如果您为此使用两个代码库或一个代码库,这并不重要。如果是这种情况,那么它在 Python 2.6 中工作的唯一方法就是嵌套它们。我想您可以尝试编写某种自定义 2to3 修复程序,将未嵌套的 2.7 代码转换为嵌套的 2.6 代码。但老实说,在您放弃 2.6 支持之前,只使用带有嵌套管理器的单个代码库会不会那么痛苦。

于 2013-10-01T21:42:05.373 回答
1

您始终nested可以自己重新实现并将其保存在compatibility.py项目中的文件中。这通常是跨版本所做的。

编辑:我看到@JBernardo 已经在评论中提到了这个解决方案。

于 2013-10-01T21:39:23.653 回答