我只想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
-able对象!
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
,你就可以开始了!最好的方法是将其封装在一个函数中并使用return
:
def do_it():
with open(path) as f:
print 'before condition'
if <condition>:
return
print 'after condition'
This is an ancient question, but this is an application for the handy "breakable scope" idiom. Just imbed your with
statement inside:
for _ in (True,):
with open(path) as f:
print 'before condition'
if <condition>: break
print 'after condition'
This idiom creates a "loop", always executed exactly once, for the sole purpose of enclosing a block of code inside a scope that can be broken out of conditionally. In OP's case, it was a context manager invocation to be enclosed, but it could be any bounded sequence of statements that may require conditional escape.
The accepted answer is fine, but this technique does the same thing without needing to create a function, which is not always convenient or desired.
我认为你应该重构逻辑:
with open(path) as f:
print 'before condition checked'
if not <condition>:
print 'after condition checked'
由于break
只能在循环内发生,因此您的选项在以下范围内受到限制with
:
return
如果您可以在函数中隔离 thewith
和相关的语句(仅此而已),那么拥有一个函数并使用可能是最干净和最简单的解决方案。
否则在需要时在内部生成异常with
,立即在下方/外部捕获with
以继续其余代码。
更新:正如 OP 在下面的评论中建议的那样(也许是脸颊上的舌头?),人们也可以将with
语句包装在一个循环中以break
使其工作 - 尽管这在语义上会产生误导。因此,虽然是一个可行的解决方案,但可能不是推荐的东西)。
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__()
您可以将所有内容放在一个函数中,当条件为真时调用返回。
这是使用try
and的另一种方法except
,即使反转条件可能更方便。
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
这个问题是在 Python 3.4 存在之前被问到的,但是在 3.4 中你可以使用contextlib.supress
,抑制你自己的个人异常。
看到这个(按原样运行)代码
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')
注意:如果您(仍然)在 3.4 之前,您仍然可以suppress
轻松制作自己的上下文管理器。
从“break”更改为“f.close”
with open(path) as f:
print('before condition')
if <condition>: f.close()
print('after condition')