我只想在特定条件下退出一个with
语句:
with open(path) as f:
print 'before condition'
if <condition>: break #syntax error!
print 'after condition'
当然,上述方法行不通。有没有一种方法可以做到这一点呢?(我知道我可以反转条件:if not <condition>: print 'after condition'
——是否有类似于上述的方式?)
我只想在特定条件下退出一个with
语句:
with open(path) as f:
print 'before condition'
if <condition>: break #syntax error!
print 'after condition'
当然,上述方法行不通。有没有一种方法可以做到这一点呢?(我知道我可以反转条件:if not <condition>: print 'after condition'
——是否有类似于上述的方式?)
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
包装您已有的内容,就可以开始了!fragile()
是可重用的。 - Mikhailpass
。在这种情况下保留或省略 pass
是个人喜好的问题。 - Orez最好的方法是将其封装在一个函数中,然后使用 return
:
def do_it():
with open(path) as f:
print 'before condition'
if <condition>:
return
print 'after condition'
__exit__
。 - Asclepius这是一个古老的问题,但这是一个方便的“可中断作用域”习语的应用程序。只需将您的with
语句嵌入其中:
for _ in (True,):
with open(path) as f:
print 'before condition'
if <condition>: break
print 'after condition'
这个成语创建了一个“循环”,始终只执行一次,唯一目的是将一个代码块封装在一个范围内,以便可以有条件地中断。在 OP 的情况下,它是用来封装上下文管理器调用的,但它也可以是任何需要有条件跳出的有界语句序列。
被接受的答案很好,但是这种技术可以在不需要创建函数的情况下完成相同的操作,而这种操作并不总是方便或者所期望的。
while True
变体),并且你还为这个习惯用语取了一个名字。 - jmilloy我认为你应该重新构思逻辑:
with open(path) as f:
print 'before condition checked'
if not <condition>:
print 'after condition checked'
with
语句封装在函数中并使用return
或引发异常一样好的解决方案。坦率地说,在许多情况下,我认为这将是最优雅和易读的解决方案。 - senderle由于 break
只能在循环内部发生,因此在 with
中,您的选项有些受限:
如果您可以将 with
和相关语句(以及其他内容)隔离在一个函数内部,那么拥有一个函数并使用 return
可能是最干净和最简单的解决方案。
否则,在需要时在 with
内部生成异常,立即在 with
下方/外部捕获以继续进行其余代码。
更新:正如 OP 在下面的评论中建议的那样(也许是开玩笑?),您还可以将 with
语句包装在一个循环中,以使 break
生效 - 虽然这会导致语义上的误导。因此,虽然它是一种可行的解决方案,但可能不是推荐的方法)。
return
进行检查,但你只能从函数块中返回,而不能从 with
块中返回。我相信你知道这一点,但你的写法让人觉得 return
只会停止 with
块中剩余代码的执行,而实际上它还会阻止同一函数中 with
块后面的任何代码的执行。 - jmilloywith
块像try
块一样,可以干净地跟随异常情况。如果可以的话,这就是我会做的。 - jmilloyfor i in [0]
这样在里面包装一个愚蠢的循环,这样你就可以打破它。 - jmilloywhile True:
作为结构。但从语义上来说,对于以后查看代码的其他人来说,这可能会产生误导。我认为在函数内部使用return
(如果with+statements
可以这样工作的话),然后跟随异常是最好的选择。 - Levon这个问题是在Python 3.4出现之前提出的,但在3.4中,您可以使用contextlib.suppress
来抑制自己的个人异常。
看看这个(可以直接运行)代码:
from contextlib import suppress
class InterruptWithBlock(UserWarning):
"""To be used to interrupt the march of a with"""
condition = True
with suppress(InterruptWithBlock):
print('before condition')
if condition: raise InterruptWithBlock()
print('after condition')
# Will not print 'after condition` if condition is True.
使用问题中的代码,您可以执行以下操作:
with suppress(InterruptWithBlock) as _, open(path) as f:
print('before condition')
if <condition>: raise InterruptWithBlock()
print('after condition')
suppress
上下文管理器。f = open("somefile","r")
for line in f.readlines():
if somecondition: break;
f.close()
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
while True
:while True:
with open(path) as f:
print 'before condition'
if <condition>:
break
print 'after condition n'
break
为此,存在一个名为__exit__()
的函数。语法如下:
with VAR = EXPR:
try:
BLOCK
finally:
VAR.__exit__()
if not <condition>
是不可取的。 - senderle