2017-07-19 24 views
4

有時我需要一個虛擬的上下文管理器,它什麼都不做。它可以作爲一個更有用,但可選的上下文管理器的替身。例如:如何在Python中編寫空(無操作)上下文管理器?

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

如何定義這樣一個瑣碎的空的上下文管理器? Python庫是否提供一個現成的產品?

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

with ctx_mgr as resource: 
    <operations on resource> 
+1

如果'if 1:'替代''with whatever:''? – Alfe

回答

9

斷裂:Python的3.7將專門爲這個原因(commit)提供nullcontext。我將在可用時更新鏈接到文檔。

對於3.7之前的Python版本:標準庫不提供專門爲這些用例設計的上下文管理器。

然而,事實證明,contextlib.suppress(自3.4版本)可用於在第一種情況下該目的,即當沒有as子句:

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

with ctx_mgr: 
    ... 

因爲Python 3.3,類似的工作 - 周圍也是可用的,contextlib.ExitStack,儘管比suppress慢(這在我的測試中需要兩倍的時間)。

如果您需要as子句,或者在使用3.3以前的Python版本時,開發人員需要自行開發。 這裏是一個可能的實現(見注在底部,但所有的錯誤都是我的):

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() 

來源:A Python feature request。非常感謝那些爲這次討論做出貢獻的人。這是我在一個自我回答的問題中總結其結果的嘗試,以節省人們閱讀那條冗長的線索的時間。另請參閱Python文檔中提到的this use of ExitStack

+1

該文檔提到ExitStack是一個無所事事的上下文管理器在這裏https://docs.python.org/3/library/contextlib.html#simplifying-support-for-single-optional-context-managers – Gribouillis

+0

我站在糾正 - 固定,謝謝。 – Julian

+1

** UPD 2017年11月23日**,最後,有一個'nullcontext'提交https://bugs.python.org/issue10049#msg306770 – maxkoryukov

0

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

相關問題