Named loops for breaking

Alf P. Steinbach alfps at start.no
Wed Mar 10 17:53:09 EST 2010


* James Harris:
> On 10 Mar, 06:29, "Gabriel Genellina" <gagsl-... at yahoo.com.ar> wrote:
>> En Tue, 09 Mar 2010 18:41:10 -0300, Daniel Klein <bri... at gmail.com>  
>> escribi :
>>
>>> Basically I'm wondering if there are any plans to implemented named
>>> loops in Python, so I can tell a break command to break out of a
>>> specific loop in the case of nested loops.
>> See PEP3136 [1] and its rejection note [2]
>> I think you may find some more discussion in the python-ideas list.
>>
>>> Currently I'm using boolean
>>> flag variables, but I find that very clumsy. I know this idea of
>>> breaking out of specific loops from javascript; I guess java does it
>>> too. It just seems a very Pythonian idea to me: clear, promotes code
>>> legibility, seems obvious.
>> Although I've occasionally missed the feature myself, I agree with Guido's  
>> arguments against it.
> 
> I don't agree with Guido's second reason in particular. He writes in
> the link Gabriel provided
> 
>   > [2]http://mail.python.org/pipermail/python-3000/2007-July/
> 008663.html
> 
> G> However, I'm rejecting it on the basis that code so complicated to
> G> require this feature is very rare. In most cases there are existing
> G> work-arounds that produce clean code, for example using 'return'.
> G> While I'm sure there are some (rare) real cases where clarity of
> the
> G> code would suffer from a refactoring that makes it possible to use
> G> return, this is offset by two issues:
> 
> G> 1. The complexity added to the language, permanently. This affects
> not
> G> only all Python implementations, but also every source analysis
> tool,
> G> plus of course all documentation for the language.
> 
> Guido may have a point here about source tools but I don't think the
> language becomes more complex. If anything it would become more
> orthogonal - i.e. fewer arbitrary restrictions. And documentation is
> needed for any change so saying that documentation would need to be
> updated is an odd reason to reject a change.
> 
> G> 2. My expectation that the feature will be abused more than it will
> be
> G> used right, leading to a net decrease in code clarity (measured
> across
> G> all Python code written henceforth). Lazy programmers are
> everywhere,
> G> and before you know it you have an incredible mess on your hands of
> G> unintelligible code.
> 
> Breaking out of an inner loop is just as natural as breaking out of
> the immediately enclosing loop. ISTM that if one is allowed the other
> should be also.
> 
>> You have several alternatives: refactor the loop  
>> into an auxiliary function, use a specific exception, add boolean flags,  
>> or repeat the test at the outer levels. (I usually choose the first).
> 
> The auxiliary function idea (Guido's preference as well as Gabriel's)
> works but it may require accessing of variables which don't appear in
> the function interface, and the "return" in that function is no
> different from the break dropping through multiple levels. Return does
> exactly that (as well as setting a result value).
> 
> There are often times when it *is* better to factor out the code to a
> different function but adding a function just to enable a break from
> an inner loop doesn't seem to me a good reason.

Gabriel Genellina mentioned these alternatives: "refactor the loop into an 
auxiliary function, use a specific exception, add boolean flags, or repeat the 
test at the outer levels. (I usually choose the first)"

And I agree, but in Python there is at least one more very practical 
alternative, namely /flatting/ the nested loops, representing them as a single loop.

It can go like this  --  very artifical construed example:


<code>
from __future__ import print_function
try:
     range = xrange
except:
     pass

def inclusive_range( first, last ):
     return range( first, last + 1 )

def xy_range( x_range, y_range ):
     for x in x_range:
         for y in y_range:
             yield (x, y)

def main():
     needle = 42
     x_range = inclusive_range( 1, 10 )
     y_range = inclusive_range( 1, 10 )
     pos = None
     for (x, y) in xy_range( x_range, y_range ):
         if x*y == needle:
             pos = (x, y)
             break
     if pos is None:
         print( "Sorry, {0} not found.".format( needle ) )
     else:
         print( "{0} found at {1}.".format( needle, pos ) )

main()
</code>


Cheers & hth.,

- Alf

PS: Gabriel, if you read this and don't understand it (as you mentioned in 
another thread that you never understand my postings), please just ask!



More information about the Python-list mailing list