Ответ 1
Python 3.7 и выше: используйте contextlib.nullcontext
, специально разработанный для этой 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
также доступен, 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
Тогда можно написать:
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
.