打破或退出“with”声明?

时间:2012-06-25 18:30:18

标签: python with-statement

我想在某些条件下退出with声明:

with open(path) as f:
    print 'before condition'
    if <condition>: break #syntax error!
    print 'after condition'

当然,上述方法无效。有没有办法做到这一点? (我知道我可以颠倒这个条件:if not <condition>: print 'after condition' - 任何方式都像上面那样?)

12 个答案:

答案 0 :(得分:56)

with给你带来麻烦?在这个问题上投入更多with个能够对象!

class fragile(object):
    class Break(Exception):
      """Break out of the with statement"""

    def __init__(self, value):
        self.value = value

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

    def __exit__(self, etype, value, traceback):
        error = self.value.__exit__(etype, value, traceback)
        if etype == self.Break:
            return True
        return error

只需将您要转到with的表达式与fragile以及raise fragile.Break打包,以便随时突破!

with fragile(open(path)) as f:
    print 'before condition'
    if condition:
        raise fragile.Break
    print 'after condition'

此设置的好处

  • 使用with,只使用with;不会将您的函数包装在语义上误导的一次性“循环”或一个狭隘的专用函数中,并且不会强迫您在with之后执行任何额外的错误处理。
  • 保持您的本地变量可用,而不必将它们传递给包装函数。
  • 嵌套!

    with fragile(open(path1)) as f:
        with fragile(open(path2)) as g:
            print f.read()
            print g.read()
            raise fragile.Break
            print "This wont happen"
        print "This will though!"
    

    这样,如果你想要破坏外部with,你不必创建一个新函数来包装外部fragile

  • 根本不需要重组:只需用{{1}}包装已有的内容,就可以了![/ li>

此设置的缺点

  • 实际上并没有使用'break'语句。无法赢得所有人;)

答案 1 :(得分:34)

最好的方法是将其封装在一个函数中并使用return

def do_it():
    with open(path) as f:
        print 'before condition'
        if <condition>:
            return
        print 'after condition'

答案 2 :(得分:6)

我认为你应该只重构逻辑:

with open(path) as f:
    print 'before condition checked'
    if not <condition>:
        print 'after condition checked'

答案 3 :(得分:5)

由于break只能在循环内发生,因此您的选项会在with内限制为:

  • return(在函数中加上“+”关联语句)
  • 退出(从节目保释 - 可能不理想)
  • 异常(在“with”中生成异常,在下方捕获)

如果你可以在一个函数中隔离return和相关的语句(没有别的),那么拥有一个函数并使用with可能是最干净最简单的解决方案。

否则,在需要时在with内生成异常,立即抓住with下方/外部以继续其余代码。

更新:正如OP在下面的评论中所暗示的那样(或许是脸颊?)还可以将with语句包装在循环内以使break起作用 - 虽然这在语义上会产生误导。因此,虽然是一个有效的解决方案,但可能不会推荐。)

答案 4 :(得分:3)

这是一个古老的问题,但这是一个方便易用范围的应用程序&#34;成语。只是将with声明嵌入其中:

for _ in (True,):
    with open(path) as f:
        print 'before condition'
        if <condition>: break
        print 'after condition'

这个习语创建一个&#34;循环&#34;,总是只执行一次,其唯一目的是将一段代码封闭在一个可以有条件地破坏的范围内。在OP的情况下,它是一个被包含的上下文管理器调用,但它可能是任何可能需要条件转义的有界语句序列。

接受的答案很好,但是这种技术在不需要创建功能的情况下做同样的事情,这并不总是方便或不需要。

答案 5 :(得分:2)

f = open("somefile","r")
for line in f.readlines():
       if somecondition: break;
f.close()

我认为你不能突破......你需要使用循环...

[编辑]或只是做其他人提到的功能方法

答案 6 :(得分:2)

为此目的存在函数__exit__()。语法如下:

with VAR = EXPR:
  try:
    BLOCK
  finally:
    VAR.__exit__()

答案 7 :(得分:1)

你可以把所有东西放在一个函数中,当条件为真时,调用一个返回。

答案 8 :(得分:1)

作为速记摘录:

class a:
    def __enter__(self):
        print 'enter'
    def __exit__(self ,type, value, traceback):
        print 'exit'

for i in [1]:
    with a():
        print("before")
        break
        print("after")

...

enter
before
exit

答案 9 :(得分:0)

从“休息”更改为“关闭”

with open(path) as f:
    print('before condition')
    if <condition>: f.close()
    print('after condition')

答案 10 :(得分:0)

使用97MiB

python3 -c "x = 'a' * (2 * 10 ** 8)"

答案 11 :(得分:0)

这是使用tryexcept的另一种方法,即使反转条件可能更方便。

class BreakOut(Exception): pass

try:
    with open(path) as f:
        print('before condition')
        if <condition>: 
            raise BreakOut #syntax error!
        print('after condition')
except BreakOut:
    pass