3

I am pretty new to both programming and Python. A few times now, I have created what feels like an awkward program flow, and I am wondering if I am following best practices. This is conceptually what I have wanted to do:

def pseudocode():
    while some condition is true:
        do some stuff
        if a condition is met:
            break out of the while loop
    now do a thing once, but only if you never broke out of the loop above 

What I've ended up doing works, but feels off somehow:

def pseudocode():
    while some condition is true:
        do some stuff
        if some condition is met:
            some_condition_met = True
            break out of the while loop

    if some_condition_met is False:
        do a thing

Is there a better way?

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Ben S.
  • 3,415
  • 7
  • 22
  • 43

3 Answers3

9

You're looking for while-else loop:

def pseudocode():
    while some condition is true:
        do some stuff
        if a condition is met:
            break out of the while loop
    else:
        now do a thing once, but only if you never broke out of the loop above 

From docs:

while_stmt ::=  "while" expression ":" suite
                ["else" ":" suite]

A break statement executed in the first suite terminates the loop without executing the else clause’s suite.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
3

Use an else clause to the while loop:

while some_condition:
    do_stuff()
    if a_condition_is_met:
        break
else:
    executed_when_never_broken

See the while statement documentation:

A break statement executed in the first suite terminates the loop without executing the else clause’s suite.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0

If you think about it, you might already have a perfectly good condition to use without setting a flag: the condition at the top of the while loop (or, rather, the not of it). Assuming you don't change the truthiness of your condition during the same iteration as a break, this gives you:

while something:
    do_stuff()
    if something_else:
        break
if not something:
   more_stuff()

This makes sense if you think of while as a repeated if: instead of happening once, a while keeps going until the condition becomes falsey.

But, like the other answers have mentioned, the analogy goes further: just like you don't have to spell all your ifs as

if a:
    a_stuff()
if not a:
    b_stuff()

while accepts an else that is executed if the condition at the top is tested and found to be falsey. So,

while something:
    do_stuff()
    if something_else:
       break
else:
    more_stuff()

And, same as the if/else case, this doesn't imply any further tests of the condition than what would happen anyway. In the same way that an else attached to if a won't run if the true-branch makes a falsey, an else attached to a while will never run after a break since that explicitly skips ever checking the condition again. This makes the else: equivalent to a decicated flag in every case.

This also extends to for loops, even though the analogy breaks - but it executes under similar enough rules: the else is run if the loop ends by having run its course rather than hitting a break.

lvc
  • 34,233
  • 10
  • 73
  • 98
  • 1
    Note that the `else:` clause and the `if not something` test can subtly differ. If the `while` loop condition becomes `False` during the loop **and** you use `break` during that same iteration, then the `else:` suite will not execute, but your `if` suite will. – Martijn Pieters May 28 '13 at 23:40
  • @MartijnPieters very true. I've edited the answer to account for that. – lvc May 28 '13 at 23:54