Чем заканчивается цикл while True?

Рассмотрим этот код:

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)

Я не поставил никакого оператора break, чтобы закончить этот цикл. Я не могу понять, как и почему этот цикл «пока правда» завершается? Он волшебным образом прерывается, когда видит, что больше нет подходящих элементов для удаления! Как ?

Например:

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)

правильно печатает

Count of 222's is : 0 

Учитывая, что счетчик даже не достиг значения «1», становится ясно, что list.remove() вызывает разрыв цикла while.

Но в документации для list.remove просто указано:

list.remove(x) : удалить из списка первый элемент, значение которого равно x. Он вызывает ValueError, если такого элемента нет.

и я уже подавил ValueError. Так что здесь происходит?

Следующий вариант без подавления работает должным образом и заканчивается бесконечным циклом.

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)

person 2020    schedule 04.12.2019    source источник
comment
suppress фактически перехватывает исключение после того, как он сломал while, но ваш try, except перехватывает исключение все еще внутри while, поэтому он продолжается.   -  person quamrana    schedule 04.12.2019


Ответы (2)


Удаление несуществующего элемента вызывает ошибку. Ошибка остановит цикл, и, поскольку вы подавили ее снаружи, код продолжится после подавления:

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

Если вы хотите, чтобы цикл продолжался, вы должны подавить ошибку до того, как она распространится на цикл:

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

Это означает, что цикл будет продолжать работать даже с ошибкой.

person nosklo    schedule 04.12.2019

Ваш код подавляет ошибку, которая завершает цикл. Ваш цикл в конечном итоге не может удалить другое значение из большого списка и выдает ValueError, который вы подавили, и поэтому цикл заканчивается для вас, казалось бы, чистым способом. Если вы удалите with suppress(ValueError):, вы увидите следующее: ValueError: list.remove(x): x not in list

person J0hn    schedule 04.12.2019