如何在Python中编写null(无操作)上下文管理器?

Jul*_*ian 32 python contextmanager

有时我需要一个无效的虚拟上下文管理器.然后,它可以用作更有用但可选的上下文管理器的替身.例如:

ctx_mgr = <meaningfulContextManager> if <condition> else <nullContextManager>
with ctx_mgr:
    ...
Run Code Online (Sandbox Code Playgroud)

如何定义这样一个简单的空上下文管理器?Python库是否提供现成的?

我们希望将上下文与as子句一起使用的情况如何?

with ctx_mgr as resource:
    <operations on resource>
Run Code Online (Sandbox Code Playgroud)

Jul*_*ian 40

Python 3.7及以上版本:使用contextlib.nullcontext,专门为此设计.

在Python 3.7之前,标准库不提供专门为这些用例设计的上下文管理器,但有一些解决方法.

从Python 3.4开始,contextlib.suppress可以在第一种情况下用于此目的,即当没有as子句时:

ctx_mgr = <meaningfulContextManager> if <condition> else contextlib.suppress()

with ctx_mgr:
    ...
Run Code Online (Sandbox Code Playgroud)

从Python 3.3开始,也可以使用类似的解决方法contextlib.ExitStack,虽然速度慢suppress(在我的测试中需要两倍的时间).

在Python 3.3之前,或者如果你as在Python 3.7之前需要一个子句,开发人员需要自己动手.这是一个可能的实现(请参阅底部的注释,但所有错误都是我的):

class NullContextManager(object):
    def __init__(self, dummy_resource=None):
        self.dummy_resource = dummy_resource
    def __enter__(self):
        return self.dummy_resource
    def __exit__(self, *args):
        pass
Run Code Online (Sandbox Code Playgroud)

然后可以写:

ctx_mgr = <meaningfulContextManager> if <condition> else NullContextManager(dummy_resource)

with ctx_mgr as resource:
    <operations on resource>
Run Code Online (Sandbox Code Playgroud)

当然,dummy_resource需要支持"有意义"资源所需的所有操作.因此,例如,如果有意义的上下文管理器on __enter__(),返回quack()在托管块内部生成的内容,dummy_resource则还需要支持它,尽管可能根本不做任何事情.

class DummyDuck(object):
    def quack()
        # Ssssh...
        pass

ctx_mgr = <meaningfulContextManager> if <condition> else NullContextManager(DummyDuck())

with ctx_mgr as someDuck:
    someDuck.quack()
Run Code Online (Sandbox Code Playgroud)

来源:Python功能请求.非常感谢为讨论做出贡献的所有人.这是我尝试在一个自我回答的问题中总结其结果,以节省人们阅读这个长线程的时间.另请参阅Python文档中提到的这种用法ExitStack.

  • **UPD 2017年11月23日**,最后,提交了"nullcontext"https://bugs.python.org/issue10049#msg306770 (3认同)
  • 该文档在此处将 ExitStack 称为无操作上下文管理器 https://docs.python.org/3/library/contextlib.html#simplifying-support-for-single-optional-context-managers (2认同)
  • 在 3.4 及更高版本(在 `nullcontext` 可用之前)可用的更快的无操作上下文管理器是 `contextlib.suppress`。它需要可变参数,你可以简单地不向它传递任何异常:`with suppress():` 不会抑制任何东西,而且它的开销比 `ExitStack` 少得多。 (2认同)

Mar*_*gur 7

适用于 Python 3.6 及以下(包括 2.7)的简单解决方案:

from contextlib import contextmanager

@contextmanager
def nullcontext(enter_result=None):
    yield enter_result
Run Code Online (Sandbox Code Playgroud)

从 Python 3.7 开始,您应该使用所提供的contextlib.nullcontext来代替。


Hua*_*Gao 6

从 Python 3.2 开始,memoryview(b'')可以用作无操作上下文管理器。请参阅https://docs.python.org/3/library/stdtypes.html#memoryview.release

优点

  • 无需进口

  • 适用于 3.2+

  • 大约快两倍contextlib.nullcontext

缺点

  • 您可能想添加# no-op评论。