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