[Python-ideas] if condition: break idiom

Arnaud Delobelle arnodel at googlemail.com
Sun Sep 21 20:50:12 CEST 2008


On 21 Sep 2008, at 17:48, Josiah Carlson wrote:

> On Sat, Sep 20, 2008 at 1:26 PM, Arnaud Delobelle
> <arnodel at googlemail.com> wrote:
>>
>> On 20 Sep 2008, at 20:44, Josiah Carlson wrote:
>>
>>>> On Sat, Sep 20, 2008 at 11:35 AM, Arnaud Delobelle
>>>>>
>>>>> [...] I think that this would look better:
>>>>>
>>>>> while True:
>>>>> do something
>>>>> break if condition
>>>>> do something else
>>>>>
>>>>
>>>> It gets worse ;)
>>>
>>> break if condition
>>>
>>> Also implies...
>>>
>>> continue if condition
>>>
>>
>> That's true, why not?  I don't use use continue so much but it seems
>> logical.
>>
>>> Never mind
>>>
>>> break if condition else continue
>>> continue if condition else break
>>>
>>
>> No that would be silly.
>
> Why?  It follows directly from conditional expressions as well as your
> proposed syntax?
>

I don't think it does.  This has nothing to do with conditional  
expressions.


>>> Because who would want to write...
>>> break if condition
>>> continue
>>>
>>> or
>>> continue if condition
>>> break
>>>
>>
>> The problem is: when would you need to do this?  I pointed out in my
>> original post that almost half of uses of 'break' in the py3k  
>> python source
>> come immediately after an 'if'.  Now I have never used or seen this:
>>
>>   if condition:
>>       break
>>   continue
>
> Just because *you've* never seen it, doesn't mean it shouldn't be a
> valid control structure.
>

What I'm saying is that it doesn't occur often enough to be worried  
about it.  OTOH, 'if condition: break' occurs very commonly.

[...]

> I would then point out that the cases that you are trying to fix,
> 'break if condition', you inadvertently hide the *flow control* in a
> mass of words.  Break and continue are currently happy little
> single-word statements.  Even when trailing on the same line as an
> 'if', there is a colon separating them from the if and condition.  I
> would argue that this punctuation is critical for understanding the
> idea "something conditional is happening here to your flow control".
> Without that colon, break/continue get to be the only two statements
> that get an optional 'if' suffix, whose only purpose seems to be to
> reduce line count.
>

Reducing line count was definitely not my aim (see just below)

>> What would be the point of spelling it 'break if condition else  
>> continue'?
>> It would even defeat the idea behind my suggestion, which is to  
>> make the
>> structure of a loop more obvious when you scan code: you can spot  
>> the 'break
>> if' (and 'continue if'!) statements just by scanning the left hand  
>> side of
>> the loop body.
>
> But this doesn't help in that.  Break and continue are *already*
> immediately to the right of whitespace (unless someone tries to make
> it a single line), and while the *simple* case of...
>
> for ... in ...:
>    ...
>    if condition:
>        break
>    ...
>
> ... is common, that doesn't mean that the following isn't ...
>

You forget:

     if condition: break

> for ... in ...:
>    ...
>    if condition:
>        ...
>        if other_condition:
>            break
>        ...
>    ...
>
> Which isn't greatly improved by your suggestion.

There's some truth in this.

>>> But if we can break or continue, why not others?  What's wrong  
>>> with a
>>> raise (especially if we surround everything with parens...)?
>>>
>>> (raise Exception("X")) if condition
>>>
>>> Never mind assert, yield, throw, return, ...  I hope this horse is  
>>> dead
>>> now.
>>>
>>
>> You have implied one reason why not: raise, assert, yield, throw,  
>> return all
>> take an argument which can be an if-expression, so this would make  
>> those
>> statements difficult to parse if you are human (and I suspect  
>> impossible if
>> you are the Python parser).
>
> No, I pointed out a syntax that is unambiguous.  How do I know it is
> unambiguous?  Because it's used by the yield *expression* in Python
> 2.5 and later:
>
> x = (yield y) + 1
>
> Though maybe that's a vote against yield, because the rest are
> statements and don't return anything.
>

Yes, they're statements, I wouldn't want them to be surrounded by  
parentheses.  I only proposed "break if" (and "continue if", perhaps),  
I don't see why every statement should be equipped with a trailing  
"if" as a necessary consequence.

>> The fact that neither break nor continue take arguments makes them  
>> very
>> 'poor' in the amount of meaning they convey.  That's why a lot of  
>> people
>> feel like writing the following in one single line.
>>
>>   if condition: break
>
> It's not a question of amount of meaning, it's a question of context.
> I've heard explanations at least as much saying that they thought that
> not having an indented trailer makes the code "prettier", "shorter",
> "easier to understand" as I've heard the opposite from reviewers
> arguing against the single-line if idiom.
>

     if condition: break

on a single line happens a lot, whether liked by reviewers or not.


>> Moreover, because we don't have a 'do .. while' construct, 'break'  
>> is more
>> important than in other languages to shape loops (especially while  
>> loops),
>> so I thought it would be useful to make it easier to spot.  The same
>> argument can be made about 'continue' of course.
>
> Perfectly reasonable, but then the base isn't so much...
>
> while 1:
>    ...
>    if condition: break
>    ...
>
> it's really...
>
> while 1:
>    ...
>    if condition: break
>

I don't agree with that: the absence of do .. while liberates the loop  
construct in python from its constraints and the first form above  
becomes more common.

> Which *has* an idiom in Python.
>
> first = 1
> while first or condition:
>    first = 0
>    ...
>

I would not use this, not because it is slower, but because it is  
uglier.

> And before you come back with "but that's not as fast", I'll point out
> that an assignment to a local and an or computation are pretty darn
> fast.  With psyco; even faster:
>
>>>> def test1(n):
> ...     i = 0
> ...     while 1:
> ...             i += 1
> ...             if i >= n: break
> ...
>>>> def test2(n):
> ...     i = 0
> ...     first = 1
> ...     while first or n > i:
> ...             first = 0
> ...             i += 1
> ...
>>>> t = time.time(); test1(10000000); time.time()-t
> 1.0160000324249268
>>>> t = time.time(); test2(10000000); time.time()-t
> 1.1559998989105225
>>>> import psyco
>>>> psyco.full()
>>>> t = time.time(); test1(1000000000); time.time()-t
> 1.4059998989105225
>>>> t = time.time(); test2(1000000000); time.time()-t
> 1.4060001373291016
>

My tests:

 >>> t1=timeit.Timer("test1(10000000)", "from loops import  
test1").timeit(5)
 >>> t2=timeit.Timer("test2(10000000)", "from loops import  
test2").timeit(5)
 >>> t1, t2
(5.3120660781860352, 7.4985768795013428)
 >>> t2/t1
1.4116121240084343

test1 is 41% faster, that is not negligible. I don't think the fact  
that psyco optimises the code is a valid argument.

> Worst-case, 15% more time without psyco for the *simplest* possible
> loop.  Less difference as the body of the while increases.  With
> psyco: no difference.
>
> But what about, "that's not as pretty as 'break if condition'"?  Ok,
> it's not as pretty.  But I would then point out that at least now, you
> don't have one of those "while 1:" loops that can raise eyebrows.
>

Well, they don't raise my eyebrows :)

> - Josiah

Anyway, there hasn't been a flurry of positive responses so far so I  
don't think this is going to go much further than this reply...

-- 
Arnaud




More information about the Python-ideas mailing list