This PEP proposes support for labels in Python's break and
continue statements. It is inspired by labeled break and
continue in other languages, and the author's own infrequent but
persistent need for such a feature.

The break statement allows the programmer to terminate a loop
early, and the continue statement allows the programmer to move to
the next iteration of a loop early. In Python currently, break
and continue can apply only to the innermost enclosing loop.

Adding support for labels to the break and continue statements
is a logical extension to the existing behavior of the break and
continue statements. Labeled break and continue can
improve the readability and flexibility of complex code which uses
nested loops.

For brevity's sake, the examples and discussion in this PEP usually
refers to the break statement. However, all of the examples and
motivations apply equally to labeled continue.

This requires five lines and an extra variable,
time_to_break_out_of_a, to keep track of when to break out of the
outer (a) loop. And those five lines are spread across many lines of
code, making the control flow difficult to understand.

This technique is also error-prone. A programmer modifying this code
might inadvertently put new code after the end of the inner (b) loop
but before the test for time_to_break_out_of_a, instead of after
the test. This means that code which should have been skipped by
breaking out of the outer loop gets executed incorrectly.

This could also be written with an exception. The programmer would
declare a special exception, wrap the inner loop in a try, and catch
the exception and break when you see it:

Again, though; this requires five lines and a new, single-purpose
exception class (instead of a new variable), and spreads basic control
flow out over many lines. And it breaks out of the inner loop with
break and out of the other loop with an exception, which is
inelegant. [1]

This next strategy might be the most elegant solution, assuming
condition_two() is inexpensive to compute:

for a in a_list:
...
for b in b_list:
...
if condition_one(a, b):
break
...
if condition_two(a, b):
break
...
if condition_two(a, b)
break
...

Breaking twice is still inelegant. This implementation also relies on
the fact that the inner (b) loop bleeds b into the outer for loop,
which (although explicitly supported) is both surprising to novices,
and in my opinion counter-intuitive and poor practice.

The programmer must also still remember to put in both breaks on
condition two and not insert code before the second break. A single
conceptual action, breaking out of both loops on condition_two(),
requires four lines of code at two indentation levels, possibly
separated by many intervening lines at the end of the inner (b) loop.

The control flow regarding when to break out of the outer (a) loop is
fully encapsulated in the break statement which gets executed when
the break condition is satisfied. The depth of the break statement
does not matter. Control flow is not spread out. No extra variables,
exceptions, or re-checking or storing of control conditions is
required. There is no danger that code will get inadvertently
inserted after the end of the inner (b) loop and before the break
condition is re-checked inside the outer (a) loop. These are the
benefits that labeled break and continue would bring to
Python.

This PEP is not a proposal to add GOTO to Python. GOTO allows a
programmer to jump to an arbitrary block or line of code, and
generally makes control flow more difficult to follow. Although
break and continue (with or without support for labels) can be
considered a type of GOTO, it is much more restricted. Another Python
construct, yield, could also be considered a form of GOTO -- an
even less restrictive one. The goal of this PEP is to propose an
extension to the existing control flow tools break and
continue, to make control flow easier to understand, not more
difficult.

Labeled break and continue cannot transfer control to another
function or method. They cannot even transfer control to an arbitrary
line of code in the current scope. Currently, they can only affect
the behavior of a loop, and are quite different and much more
restricted than GOTO. This extension allows them to affect any
enclosing loop in the current name-space, but it does not change their
behavior to that of GOTO.

The for and while loop syntax will be followed by an optional as
or label (contextual) keyword [2] and then an identifier,
which may be used to identify the loop out of which to break (or which
should be continued).

The break (and continue) statements will be followed by an
optional identifier that refers to the loop out of which to break (or
which should be continued). Here is an example using the as
keyword:

for a in a_list as a_loop:
...
for b in b_list as b_loop:
...
if condition_one(a, b):
break b_loop # same as plain old break
...
if condition_two(a, b):
break a_loop
...
...

Or, with label instead of as:

for a in a_list label a_loop:
...
for b in b_list label b_loop:
...
if condition_one(a, b):
break b_loop # same as plain old break
...
if condition_two(a, b):
break a_loop
...
...

This has all the benefits outlined above. It requires modifications
to the language syntax: the syntax of break and continue
syntax statements and for and while statements. It requires either a
new conditional keyword label or an extension to the conditional
keyword as. [3] It is unlikely to require any changes to
existing Python programs. Passing an identifier not defined in the
local scope to break or continue would raise a NameError.

The syntax of break and continue would be altered to allow
multiple break and continue statements on the same line. Thus,
break break would break out of the first and second enclosing
loops.

for a in a_list:
...
for b in b_list:
...
if condition_one(a,b):
break # plain old break
...
if condition_two(a,b):
break break
...
...

This would also allow the programmer to break out of the inner loop
and continue the next outermost simply by writing break continue,
[4] and so on. I'm not sure what exception would be
raised if the programmer used more break or continue
statements than existing loops (perhaps a SyntaxError?).

I expect this proposal to get rejected because it will be judged too
difficult to understand.

This proposal would not require any changes to existing Python
programs.

Rather than embellishing for and while loop syntax with labels, the
programmer wishing to use labeled breaks would be required to create
the iterator explicitly and assign it to an identifier if he or she
wanted to break out of or continue that loop from within a
deeper loop.

a_iter = iter(a_list)
for a in a_iter:
...
b_iter = iter(b_list)
for b in b_iter:
...
if condition_one(a,b):
break b_iter # same as plain old break
...
if condition_two(a,b):
break a_iter
...
...

Passing a non-iterator object to break or continue would raise
a TypeError; and a nonexistent identifier would raise a NameError.
This proposal requires only one extra line to create a labeled loop,
and no extra lines to break out of a containing loop, and no changes
to existing Python programs.

This is a variant of Proposal D. Iterators would need be created
explicitly if anything other that the most basic use of break and
continue was required. Instead of modifying the syntax of
break and continue, .break() and .continue() methods
could be added to the Iterator type.

a_iter = iter(a_list)
for a in a_iter:
...
b_iter = iter(b_list)
for b in b_iter:
...
if condition_one(a,b):
b_iter.break() # same as plain old break
...
if condition_two(a,b):
a_iter.break()
...
...

I expect that this proposal will get rejected on the grounds of sheer
ugliness. However, it requires no changes to the language syntax
whatsoever, nor does it require any changes to existing Python
programs.

I have never looked at the Python language implementation itself, so I
have no idea how difficult this would be to implement. If this PEP is
accepted, but no one is available to write the feature, I will try to
implement it myself.

To continue the Nth outer loop, you would write
break N-1 times and then continue. Only one continue would be
allowed, and only at the end of a sequence of breaks. continue
break or continue continue makes no sense.