pythonpython-3.xlistsuppress

How does this "while True" loop end?


Consider this code :

from random import randrange
from contextlib import suppress

mybiglist = [randrange(1, 100) for i in range(1000)]
count = 0
with suppress(ValueError):
    while True:
        mybiglist.remove(1)
        count += 1
print("Count of 1's is : %d "% count)

I didnt put any break statement to end this loop. I am unable to understand how and why does this "while True" loop terminate ? It magically breaks when it sees that there are no more matching elements to remove ! How ?

For example:

from random import randrange
from contextlib import suppress

mybiglist = [randrange(1, 100) for i in range(1000)]
count = 0

with suppress(ValueError):
    while True:
        mybiglist.remove(222)  # a number outside of the randrange, so zero occurrence
        count += 1
print("Count of 222's is : %d "% count)

correctly prints

Count of 222's is : 0 

Considering that count didnt even get to the value "1", it is clear that the list.remove() is causing the while loop to break.

But the documentation for list.remove just states:

list.remove(x) : Remove the first item from the list whose value is equal to x. It raises a ValueError if there is no such item.

and I have already suppressed the ValueError. So whats happening here ?

The following variant without suppress does work as expected and end up in an Infinite loop.

from random import randrange

mybiglist = [randrange(1, 100) for i in range(1000)]
count = 0

while True:
    try:
        mybiglist.remove(222)
        count += 1
    except ValueError:
        pass

print("Count of 222's is : %d "% count)

Solution

  • Removing an element that doesn't exist raises the error. The error will stop the loop, and since you suppressed it outside, the code continues after the suppression:

    with suppress(ValueError):
        while True:
            mybiglist.remove(222) # element that doesn't exist, raises error
            count += 1
    # ... code continues here
    

    If you want the loop to continue, you have to suppress the error before it propagates to the loop:

    while True:
        with suppress(ValueError):
            mybiglist.remove(222) # element that doesn't exist, raises error
            count += 1
        # ... code continues here
    

    That means the loop will continue running even with the error.