[Python-ideas] SyntaxWarning for for/while/else without break or return?

Steven D'Aprano steve at pearwood.info
Fri Oct 9 04:10:01 CEST 2009

On Thu, 8 Oct 2009 07:57:38 pm Stefan Rank wrote:
> Hi,
> a suggestion/question related to the discussion about renaming
> for/else and while/else:
> Is it easy to generate a SyntaxWarning if you use these constructs
> without a break or return statement in the loop? AFAICS, any such
> usage would be either wrong or unnecessary. (right?)

-1 on such a warning. This sort of check belongs in PyLint or 
equivalent, there is no need to complicate the compiler and make it 
part of the language.

The compiler should be nicely lean and simple and not try to guess what 
the user's intention is. for...else with no break is legal code, if 
there's no break inside it, it is still legal code.

> This would both help prevent wrong usage because of a false intuition
> and, if adequately and prominently documented, would help those
> interested in learning about for/else while/else.
> Easily doable? Maybe even make it a SyntaxError?

-1000 on making it a SyntaxError. SyntaxErrors are for things which are 
WRONG, not for things which are unnecessary or redundant or pointless.

Should this be prohibited too?

for x in seq:
    if 0: break
    print "whatever"

What happens when the break is under a __debug__ test? The same source 
compiles to two different byte-codes, one of which has break, the other 
doesn't. Given this:

code = compile("""for x in seq:
    if __debug__: break
    print "no break"
""", '', 'exec')

this is the byte-code you get running normally:

>>> dis.dis(code)
  1           0 SETUP_LOOP              20 (to 23)
              3 LOAD_NAME                0 (seq)
              6 GET_ITER
        >>    7 FOR_ITER                 7 (to 17)
             10 STORE_NAME               1 (x)

  2          13 BREAK_LOOP
             14 JUMP_ABSOLUTE            7
        >>   17 POP_BLOCK

  4          18 LOAD_CONST               0 ('no break')
             21 PRINT_ITEM
             22 PRINT_NEWLINE
        >>   23 LOAD_CONST               1 (None)
             26 RETURN_VALUE

and this is what you get running under python -O:

>>> dis.dis(code)
  1           0 SETUP_LOOP              19 (to 22)
              3 LOAD_NAME                0 (seq)
              6 GET_ITER
        >>    7 FOR_ITER                 6 (to 16)
             10 STORE_NAME               1 (x)

  2          13 JUMP_ABSOLUTE            7
        >>   16 POP_BLOCK

  4          17 LOAD_CONST               0 ('no break')
             20 PRINT_ITEM
             21 PRINT_NEWLINE
        >>   22 LOAD_CONST               1 (None)
             25 RETURN_VALUE

No break in the second case. So now we have choices:

* Code which runs fine normally becomes a SyntaxError when running 
with -O.

* for...else does not require a break when running with -O, but does 
require it without -O.

* We pile complication on top of complication and make an explicit 
exception for tests like if __debug__: break -- which means that we 
still have for loops with no break that run perfectly fine!

* Stop optimizing if __debug__ tests.

All four of these alternatives are unacceptable.

Steven D'Aprano

More information about the Python-ideas mailing list