jeff
jeff

Reputation: 1020

Infinite while loop in python - with conflicting conditions

my typo error led in the 'while loop' function led me to the following question

from time import sleep
from random import randint

def control_pressure():
    pressure = measure_pressure()
    while True:
        if pressure <= 500:
            break

        while pressure > 500 and pressure <= 700:
            run_standard_safeties()
            pressure = measure_pressure()

        while pressure > 100:                     # Here is the typo
            run_critical_safeties()
            pressure = measure_pressure()

    print("Wow! The system is safe...")

def measure_pressure():
    pressure = randint(450, 800)
    print(f"psi={pressure}", end="; ")
    return pressure

def run_standard_safeties():
    print("Running standard safeties...")
    sleep(0.2)

def run_critical_safeties():
    print("Running critical safeties...")
    sleep(0.7)

if __name__ == "__main__":
    control_pressure()

In the above, I made a typo and checked pressure > 100, while condition. But earlier in the first part of the function, it checked, while pressure <= 500, then break. So technically any value lesser than or equal to 500 should return True and break the function without reaching the pressure > 100 condition.

But this function continued without stopping. Why does it happen?

Thanks

Upvotes: 0

Views: 323

Answers (2)

paxdiablo
paxdiablo

Reputation: 881103

Your scenario is best described sequentially.

Any initial pressure greater than 500 will bypass the break and continue to the first inner loop. Since you're getting a random value 450..800 (a range of 350 - ranges here may be off by one but they're close enough so as not to matter), this has a probability of about 300/350 (the numerator comes from the 500..800 range) or 85%.

The first inner loop will then run as long as you're getting pressures in the range 500..700, a probability of about 200/350, or 57%.

At some point you'll exit that first inner loop and enter the second. And you will enter it because all values in the range 450..800, that you can possibly get as a pressure, are greater than a hundred.

That means, of course, that you will also never exit that loop because no pressure you ever get after that point will be a hundred or less, which is what's needed to exit the loop.


As an aside, you could actually avoid this loops-within-loops structure by realising that you to get the pressure every iteration of every loop, so that can be made common.

Assuming your typo was to use 100 where you meant 700 (as that marches with mutually exclusive ranges), that can be simplified to:

def control_pressure():
    while True:
        pressure = measure_pressure()
        if pressure <= 500:
            print("Wow! The system is safe...")
            return

        if pressure <= 700:
            run_standard_safeties()
        else:
            run_critical_safeties()

Or, if you want to use the := walrus operator(a) (available in Python 3.8+, I think), you could shorten it even further by getting and checking pressure as part of the while statement:

def control_pressure():
    while (pressure := measure_pressure()) > 500:
        if pressure <= 700:
            run_standard_safeties()
        else:
            run_critical_safeties()
    print("Wow! The system is safe...")

(a) So called because, if you rotate it 90° clockwise and squint, it looks like a walrus with its two eyes and two huge tusks.

It basically (in this case) lets you assign a value to a variable as part of checking said variable, so that the value is available for later checks as well.

Upvotes: 2

Ofek Glick
Ofek Glick

Reputation: 1003

If the initial number is above 100 and above 500 it will enter the second loop and never stop since it will always be above 100, since your are taking one at random from 450-800.

Upvotes: 0

Related Questions