May-10-2019, 12:04 PM
The break statement doesn't allow to exit several nested loops. It is a simple exercise to develop a
block()
context to do so. Here is an attemptfrom contextlib import contextmanager @contextmanager def block(): """Block of code context allowing to exit deeply nested loops Usage: with block() as b: ... # somewhere in a nested loop b.exit() ... """ tok = BlockToken() try: yield tok except EndOfBlock as exc: if exc.args[0] is not tok: raise class EndOfBlock(RuntimeError): """Helper exception type for the block() context""" class BlockToken: """Helper class for block() context""" def exit(self): raise EndOfBlock(self) def func(x): """Test function for the block() context""" result = '' with block() as outer: result += 'A' for i in range(4): result += 'B' if x > 0 and i > 2: outer.exit() result += 'D' with block() as inner: result += 'C' if x == 1: outer.exit() elif x == 2: inner.exit() result += 'E' result += 'F' result += 'G' result += 'H' return result if __name__ == '__main__': assert func(0) == "ABDCEFBDCEFBDCEFBDCEFGH" assert func(1) == "ABDCH" assert func(2) == "ABDCFBDCFBDCFBH" print('SUCCESS')An interesting feature here is that the
BlockToken
instance can be used as argument for functions called within the block. For example you could writedef do_something(session): if input('Do you want to quit?').strip().lower() in ('y', 'yes'): session.exit() for i in range(5): print(i) with block() as user_session: do_something(user_session) print("If we're here, the user chose to stay!")