簡體   English   中英

如何在 Python 中編寫空(無操作)上下文管理器?

[英]How do I write a null (no-op) contextmanager in Python?

有時我需要一個什么都不做的虛擬上下文管理器。 然后它可以用作更有用但可選的上下文管理器的替代品。 例如:

ctx_mgr = <meaningfulContextManager> if <condition> else <nullContextManager>
with ctx_mgr:
    ...

我如何定義這樣一個微不足道的空上下文管理器? Python 庫是否提供現成的?

我們希望上下文與as子句一起使用的情況如何?

with ctx_mgr as resource:
    <operations on resource>

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:
    ...

從 Python 3.3 開始,也可以使用類似的解決方法, contextlib.ExitStack ,盡管比suppress慢(在我的測試中它需要兩倍的時間)。

在 Python 3.3 之前,或者如果您需要在 Python 3.7 之前as子句,開發人員需要自己滾動。 這是一種可能的實現(請參閱底部的注釋,但所有錯誤都是我的):

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

然后可以寫:

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

with ctx_mgr as resource:
    <operations on resource>

當然, dummy_resource將需要支持“有意義”資源所需的所有操作。 因此,例如,如果有意義的上下文管理器,在__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()

來源:一個 Python 功能請求 非常感謝所有參與討論的人。 這是我在一個自我回答的問題中總結其結果的嘗試,以節省人們閱讀那條長線的時間。 另請參閱 Python 文檔中提到ExitStack這種用法

適用於 Python 3.6 及以下(包括 2.7)的簡單解決方案:

from contextlib import contextmanager

@contextmanager
def nullcontext(enter_result=None):
    yield enter_result

從 Python 3.7 開始,您應該改用提供的contextlib.nullcontext

從 Python 3.2 開始, memoryview(b'')可以用作無操作上下文管理器。 請參閱https://docs.python.org/3/library/stdtypes.html#memoryview.release

優點

  • 不需要進口

  • 適用於 3.2+

  • 大約是contextlib.nullcontext兩倍

缺點

  • 您可能想要添加# no-op注釋。

Python 2.7 的簡單解決方案,答案中尚未提及:

from contextlib import nested
with nested():
    ...

對於 Python 2.7+ ,您可以使用

import contextlib
with (lambda noop_func: contextlib.contextmanager(noop_func))(lambda: (yield))():
    print("hi")

我只是使用threading.Lock()作為虛擬上下文管理器。 臨時鎖,僅供上下文管理器使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM