Python 3.7及以上版本:使用contextlib.nullcontext
,该函数专门为此目的设计。
在Python 3.7之前,标准库中没有专门为这些用例设计的上下文管理器,但是有一些变通方法。
自Python 3.4起,可以在第一种情况下(即没有as
子句时)使用contextlib.suppress
来实现这个目的:
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__()
中返回一个在托管块内呱呱叫的东西,dummy_resource
也将需要支持,尽管可能什么也不做。
class DummyDuck(object):
def quack()
pass
ctx_mgr = <meaningfulContextManager> if <condition> else NullContextManager(DummyDuck())
with ctx_mgr as someDuck:
someDuck.quack()
来源:一个Python功能请求。非常感谢所有为讨论做出贡献的人。这是我尝试在一个自问自答的问题中总结其结果,以节省大家阅读那个冗长线程的时间。还请参阅Python文档对使用ExitStack
的提及。
if 1:
替代with whatever:
怎么样? - Alfe