如何在执行上下文的情况下停止Python中的语句?

时间:2012-11-30 05:20:57

标签: python

我有一些像这样的代码:

with SomeContext(args):
  <statement1>
  .
  .
  <statementN>

我希望此代码的行为如下:

if some_condition(args):
  f1()
else:
  <statement1>
  .
  .
  <statementN>

else块中的语句也需要访问args。

但我希望隐藏f1some_condition来自此抽象的用户,因此使用if-else块是不可选的。另外,我不想强​​制用户使用约束来包装函数中的所有语句。是否有可能在允许这个的with上下文中做一些python魔术?

2 个答案:

答案 0 :(得分:3)

我能得到的最接近的是使用两个嵌套的上下文管理器,如下所示:

class SkippedException(Exception):
    pass

class SkipContext:
    def __enter__(self):
        pass
    def __exit__(self, type, value, tb):
        return type is SkippedException

class SomeContext:
    def __init__(self, arg):
        self.arg = arg
    def __enter__(self):
        if self.arg == 1:
            print "arg", self.arg
            raise SkippedException()
    def __exit__(self, type, value, tb):
        pass

with SkipContext(), SomeContext(1):
    print "body"

SkipContext的情况下,SkippedException经理基本上会抓住内部SomeContext经理提出的arg == 1

请注意,只有Python 2.7或更高版本支持多个上下文表达式的语法。在早期版本中,您必须写:

with SkipContext():
    with SomeContext(1):
        print "body"

尽管文档中有声明,contextlib.nested上下文管理器在with内抛出异常时与上述嵌套__enter__语句的语义不完全匹配,因此它不会在这种情况下工作。

应该注意PEP 343提到应该不鼓励隐藏流控制的宏(如上下文管理器),并引用Raymond Chen's rant against hidden flow control

答案 1 :(得分:-1)

是的,您可以轻松地创建如下的上下文管理器。

import contextlib

@contextlib.contextmanager
def SomeContext(args):
    if some_condition(args):
        f1()
    else:
        yield

用户的包装代码在yield点执行。我不认为上下文管理器有时不执行用户代码是一个问题,但我没有检查过。