根据情况使用不同的上下文管理器

时间:2018-10-01 13:16:18

标签: python python-3.x with-statement contextmanager

是否可以根据情况使用不同的上下文管理器执行单个块?

示例:

if some_condition:
    with ContextManager(**args) as contex:
        ... # some block
else:
    with OtherContextManager(**other_args) as contex:
        ... # the same block

一种方法是将...包装到一个函数中,但这对我来说可能不太方便。还有另一种可能性吗?

3 个答案:

答案 0 :(得分:4)

您可以将构造的对象存储在变量中,例如:

if some_condition:
    cm = ContextManager(**args)
else:
    cm = OtherContextManager(**other_args)

with cm as contex:
        ... # some block

以上内容可以轻松扩展到三个可能的上下文管理器等。您还可以决定例如在“输入”上下文之前先“修补”上下文管理器。

尽管通常会看到类似with foo() as bar:的模式,但实际上Python只是对foo()求值,获取该元素,然后在对象上调用.__enter__()。该方法的结果存储在bar中。

因此,foo() 调用没有任何“特殊”之处,您可以在左侧使用任何类型的对象。因此,您可以例如将if-else逻辑封装在一个单独的函数中,然后返回上下文管理器,然后使用该变量,或者将上下文管理器作为参数传递。只要您在with语句中使用它,Python就会在幕后调用.__enter__(..).__exit__(..)

答案 1 :(得分:2)

怎么样...

with ContextManager(**args) if some_condition else OtherContextManager(**other_args) as contex:
    ... # some block

...?

答案 2 :(得分:2)

我们可以发疯,利用__enter____exit__都是方法,并且在原始对象中调用它们(而不是{{1}返回的对象)这一事实}):

__enter__

并像这样使用它:

class WrapperContext:

 def __init__(self, condition):
     if condition:
         self.real_context = ContextA()
     else:
         self.real_context = ContextB()

 def __enter__(self):
     return self.real_context.__enter__()

 def __exit__(self):
     return self.real_context.__exit__()