[英]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.