如何根据上下文管理器的参数省略代码块?

时间:2014-03-30 11:54:13

标签: python contextmanager

让我们看看这个例子:

with mycontextmanager(arg1='value', arg2=False):
    print 'Executed'

是否有办法在基于参数的上下文管理器中执行代码块(print 'Executed'),例如:当arg2不是False时?

2 个答案:

答案 0 :(得分:1)

另一个选项是使用特殊的ConditionalExecution上下文管理器,其__enter__方法返回一个有条件地引发SkipExecution异常的操作。 __exit__方法仅抑制此异常。 如下所示:

class SkipExecution(Exception): pass

class ConditionalExecution(object):
    def __init__(self, value, arg):
        self.value = value
        self.arg = arg
    def __enter__(self):
        def action():
            if not self.arg:
                raise SkipExecution()
        return action
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is SkipExecution:
            return True
        return False

用作:

In [17]: with ConditionalExecution(1, True) as check_execution:
    ...:     check_execution()
    ...:     print('Hello')
    ...:     
Hello

In [18]: with ConditionalExecution(1, False) as check_execution:
    ...:     check_execution()
    ...:     print('Hello')

In [19]: 

但问题是您必须添加对返回值的调用。

问题是__exit__被称为当且仅当 __enter__成功返回时,这意味着您无法在__enter__中引发异常以阻止代码块的执行。 如果您愿意,可以修改此解决方案,以便可以在第一行完成对check_execution()的调用,例如:

In [29]: with ConditionalExecution(1, True) as check_execution, check_execution():
    ...:     print('Hello')
Hello

In [30]: with ConditionalExecution(1, False) as check_execution, check_execution():
    ...:     print('Hello')

使用Skipper助手上下文管理器:

class SkipExecution(Exception): pass

class Skipper(object):
    def __init__(self, func):
        self.func = func
    def __call__(self):
        return self.func() or self
    def __enter__(self):
        return self
    def __exit__(self, *args):
        pass

class ConditionalExecution(object):
    def __init__(self, value, arg):
        self.value = value
        self.arg = arg
    def __enter__(self):
        def action():
            if not self.arg:
                raise SkipExecution()
        return Skipper(action)
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is SkipExecution:
            return True
        return False

如果没有至少一个显式的函数调用,我认为无论如何都没有这样做。如上例所示。

答案 1 :(得分:0)

也许这样,假设你的上下文管理器支持一个“what”属性,它暴露了初始化时在arg2中得到的值:

with mycontextmanager(arg1='value', arg2=False) as ctx:
    if ctx.whatever:
        print 'Executed'