Цикл while в Python: break, continue и else

Обновлено:

В первой части мы познакомились с базовой конструкцией:

while condition:
    ...

Теперь посмотрим, как внутри while использовать:

if
elif
else
input()

а также познакомимся с:

break
continue

и конструкцией:

while ...:
    ...
else:
    ...

while вместе с input()

1. Цикл может постоянно запрашивать данные

Например, программа собирает числа пользователя и складывает их.

Пока мы ещё не знаем break, можно заранее создать специальное значение:

user_input = None
total = 0

while user_input != 'exit':
    user_input = input(
        'Введите число или exit: '
    ).strip()

    if user_input.removeprefix('-').isdecimal():
        number = int(user_input)

        total += number
    elif user_input != 'exit':
        print('Введите целое число')

print(f'Сумма: {total}')

Пользователь может вводить:

Введите число или exit: 10
Введите число или exit: 25
Введите число или exit: -5
Введите число или exit: exit

Результат:

Сумма: 30

2. Почему заранее создаём user_input

В условии:

while user_input != 'exit':

имя:

user_input

должно существовать уже при первой проверке условия.

Поэтому заранее пишем:

user_input = None

Первая проверка:

None != 'exit'

даёт:

True

и цикл начинается.

Позже мы познакомимся с break, который позволяет решить эту задачу проще.


Добавление значений в список

3. Ещё один пример

Программа собирает названия технологий:

technology = None
technologies = []

while technology != 'exit':
    technology = input(
        'Введите технологию или exit: '
    ).strip()

    if technology == 'exit':
        print('Ввод завершён')
    elif technology:
        technologies.append(technology)

print(technologies)

Например:

Введите технологию или exit: Python
Введите технологию или exit: SQL
Введите технологию или exit: Django
Введите технологию или exit: exit

Получим:

['Python', 'SQL', 'Django']

Строка:

exit

в список не добавилась.


Проверка пароля

4. Повторяем ввод до правильного значения

password = 'python123'

user_password = None
wrong_attempts = 0

while user_password != password:
    user_password = input(
        'Введите пароль: '
    )

    if user_password != password:
        wrong_attempts += 1

        print('Неверный пароль')

print('Пароль верный')

print(
    f'Неверных попыток: {wrong_attempts}'
)

Пока пароль неправильный, условие:

user_password != password

остаётся True.

Как только строки совпали, при следующей проверке условие становится:

False

и цикл заканчивается.


Обход цифр целого числа

5. Последняя цифра

Мы уже знаем:

number % 10

позволяет получить последнюю цифру положительного целого числа.

Например:

number = 5837

last_digit = number % 10

print(last_digit)

Результат:

7

А:

number // 10

позволяет убрать последнюю цифру:

number = 5837

number = number // 10

print(number)

Результат:

583

6. Обходим все цифры

number = 5837

while number > 0:
    digit = number % 10

    print(digit)

    number //= 10

Результат:

7
3
8
5

Мы получаем цифры справа налево.


7. Как работает алгоритм

Начинаем:

5837

Первая итерация:

5837 % 10 → 7
5837 // 10 → 583

Вторая:

583 % 10 → 3
583 // 10 → 58

Дальше:

58 % 10 → 8
58 // 10 → 5

5 % 10 → 5
5 // 10 → 0

После этого:

number > 0

становится False.


8. Можно собирать цифры в список

number = 5837
digits = []

while number > 0:
    digit = number % 10

    digits.append(digit)

    number //= 10

print(digits)

Результат:

[7, 3, 8, 5]

Цифры находятся в обратном порядке, потому что мы каждый раз забирали последнюю.

Для отрицательного числа перед таким алгоритмом можно работать с:

abs(number)

Отдельно нужно учитывать число 0, потому что условие:

while number > 0:

для него сразу будет False.


randint()

9. Случайное целое число

В модуле:

random

есть функция:

randint()

Например:

from random import randint


number = randint(1, 10)

print(number)

При разных запусках можно получить:

3

или:

8

или:

10

и так далее.


10. Обе границы включаются

Вызов:

randint(1, 10)

может вернуть любое целое число:

1, 2, 3, ..., 9, 10

То есть включаются:

1

и:

10

break

11. Немедленный выход из цикла

Ключевое слово:

break

полностью завершает ближайший цикл.

Например:

from random import randint


count = 0

while count < 10:
    number = randint(1, 10)

    print(number)

    count += 1

    if number == 5:
        break

Здесь возможно два варианта завершения цикла.

Первый:

count достиг 10

Второй:

randint() вернул 5
↓
break
↓
немедленный выход

12. break не ждёт следующей проверки while

Например:

while count < 10:
    ...

    if number == 5:
        break

    print('Конец итерации')

Если:

number == 5

выполняется:

break

и Python сразу покидает цикл.

Строка:

print('Конец итерации')

в этой итерации уже не выполнится.


Пароль с break

13. Код становится проще

Раньше:

password = 'python123'
user_password = None

while user_password != password:
    user_password = input(
        'Введите пароль: '
    )

    if user_password != password:
        print('Неверный пароль')

Теперь можно написать:

password = 'python123'
wrong_attempts = 0

while True:
    user_password = input(
        'Введите пароль: '
    )

    if user_password == password:
        break

    wrong_attempts += 1

    print('Неверный пароль')

print('Пароль верный')

print(
    f'Неверных попыток: {wrong_attempts}'
)

Нам больше не нужно заранее создавать:

user_password = None

Цикл специально делаем бесконечным:

while True:

и самостоятельно определяем момент выхода:

if user_password == password:
    break

continue

14. Пропустить остаток текущей итерации

continue не завершает весь цикл.

Оно завершает только текущую итерацию и сразу возвращает выполнение к следующей проверке while.

Например:

number = 0

while number < 10:
    number += 1

    if number == 5:
        continue

    print(number)

Результат:

1
2
3
4
6
7
8
9
10

Число:

5

не было напечатано.


15. Как работает continue

Когда:

number == 5

Python встречает:

continue

и не выполняет оставшуюся часть тела:

print(number)

Вместо этого сразу переходит к:

while number < 10:

и начинает следующую итерацию.


Важно с изменением счётчика

16. continue может случайно создать бесконечный цикл

Например:

number = 0

while number < 10:
    if number == 5:
        continue

    number += 1

Когда number станет:

5

выполнится:

continue

Строка:

number += 1

будет пропущена.

На следующей итерации number всё ещё:

5

Снова выполняется continue.

Получаем бесконечный цикл.

Поэтому всегда важно проверять:

Не пропускает ли continue изменение значения, от которого зависит завершение while.


Пример с randint() и continue

17. Пропускаем определённое случайное число

from random import randint


count = 0

while count < 10:
    count += 1

    number = randint(1, 10)

    if number == 7:
        continue

    print(number)

Здесь выполняется ровно до десяти генераций.

Если выпала:

7

мы просто не печатаем её и переходим к следующей итерации.

Важно, что:

count += 1

выполняется до continue.

Поэтому счётчик всё равно движется к завершению цикла.


else у while

18. else можно написать на одном уровне с while

while condition:
    ...
else:
    ...

Этот else связан именно с циклом.

Он выполняется, если цикл закончился обычным способом — потому что условие while стало ложным.


19. Пример с randint()

from random import randint


count = 0

while count < 10:
    number = randint(1, 10)

    print(number)

    count += 1

    if number == 5:
        print('Нашли 5')

        break
else:
    print(
        'За 10 попыток число 5 '
        'не выпало'
    )

Здесь есть два варианта.

Выпало 5

...
5
Нашли 5

Выполняется:

break

Поэтому блок:

else:

не выполняется.


5 не выпало

После десяти итераций:

count < 10

становится:

False

Цикл заканчивается обычным способом.

Тогда выполняется:

else:

и программа печатает:

За 10 попыток число 5 не выпало

Главное правило while ... else

20. else связан с отсутствием break

Можно запомнить:

цикл закончился без break
→ else выполняется

цикл закончился через break
→ else пропускается

Именно поэтому else у цикла особенно полезен в задачах поиска.


Практический пример break + else

21. Поиск значения

numbers = [
    10,
    25,
    30,
    47,
    60,
]

index = 0

while index < len(numbers):
    if numbers[index] == 47:
        print(
            f'Найден индекс: {index}'
        )

        break

    index += 1
else:
    print('Значение не найдено')

Если 47 найдено:

Найден индекс: 3

else не выполняется.

Если удалить 47 из списка, цикл закончится потому, что:

index < len(numbers)

станет False.

Тогда:

Значение не найдено

break, continue и else

Коротко:

break
→ полностью выйти из цикла

continue
→ закончить только текущую итерацию
  и перейти к следующей

while ... else
→ выполнить else,
  если цикл завершился без break

Обход списка с помощью while

22. От начала к концу

fruits = [
    'apple',
    'banana',
    'orange',
    'mango',
]

index = 0
fruits_length = len(fruits)

while index < fruits_length:
    print(
        fruits[index]
    )

    index += 1

Результат:

apple
banana
orange
mango

23. Как работает обход

Начинаем:

index = 0

Получаем:

fruits[0]

Затем:

index += 1

и получаем:

fruits[1]

Дальше:

fruits[2]
fruits[3]

Когда:

index == 4

условие:

index < fruits_length

становится:

4 < 4 → False

Цикл заканчивается.


Такой же принцип работает со строкой

24. Обход по индексам

word = 'Python'

index = 0
word_length = len(word)

while index < word_length:
    print(word[index])

    index += 1

Результат:

P
y
t
h
o
n

Тот же принцип можно использовать для других объектов, поддерживающих индексацию.


Обход в обратном порядке

Возьмём:

fruits = [
    'apple',
    'banana',
    'orange',
    'mango',
]

Разберём три способа.


25. Способ №1. Отрицательный индекс через положительный счётчик

index = 1

while index <= len(fruits):
    print(
        fruits[-index]
    )

    index += 1

Получаем:

mango
orange
banana
apple

Используются индексы:

-1
-2
-3
-4

26. Способ №2. Положительные индексы справа налево

index = len(fruits) - 1

while index >= 0:
    print(
        fruits[index]
    )

    index -= 1

Сначала вычисляем индекс последнего элемента:

len(fruits) - 1

Для четырёх элементов:

4 - 1 = 3

Дальше:

3
2
1
0

27. Способ №3. Только отрицательные индексы

index = -1

while index >= -len(fruits):
    print(
        fruits[index]
    )

    index -= 1

Получаем индексы:

-1
-2
-3
-4

и снова обходим список от последнего элемента к первому.


Нужно ли каждый раз вызывать len()

28. Два варианта

Можно написать:

index = 0

while index < len(values):
    index += 1

Функция:

len(values)

будет вызываться при каждой проверке условия.


Можно заранее сохранить длину:

index = 0
values_length = len(values)

while index < values_length:
    index += 1

Теперь len() вызывается только один раз.


29. Небольшой эксперимент

from timeit import timeit


values = range(5_000)


def solve1(items):
    index = 0

    while index < len(items):
        index += 1


def solve2(items):
    index = 0
    items_length = len(items)

    while index < items_length:
        index += 1


print(
    timeit(
        lambda: solve1(values),
        number=30_000,
    )
)

print(
    timeit(
        lambda: solve2(values),
        number=30_000,
    )
)

Второй вариант может оказаться быстрее, потому что:

len(items)

не вызывается при каждой итерации.

Конкретная разница зависит от:

  • версии Python;
  • компьютера;
  • типа объекта;
  • количества итераций.

Поэтому нельзя рассчитывать на универсальное правило вроде:

всегда ровно в два раза быстрее

30. Когда длину удобно сохранять заранее

Если длина объекта во время цикла не должна изменяться, запись:

items_length = len(items)

может быть полезна:

  • меньше повторяющихся вызовов;
  • условие становится проще;
  • явно видно, с какой длиной работает алгоритм.

Например:

fruits_length = len(fruits)

while index < fruits_length:
    ...

31. Когда нужно быть осторожным

Если внутри цикла сам список изменяет длину:

items.append(...)

или:

items.pop()

заранее сохранённое:

items_length

уже может не соответствовать текущему:

len(items)

Поэтому решение зависит от алгоритма.


Главное по второй части

Внутри while можно использовать обычные конструкции Python:

input()
if
elif
else

Например:

while condition:
    value = input(...)

    if ...:
        ...
    elif ...:
        ...
    else:
        ...

break полностью завершает цикл:

if condition:
    break

continue завершает только текущую итерацию:

if condition:
    continue

При использовании continue важно не пропустить изменение переменной, от которой зависит завершение while.


Конструкция:

while condition:
    ...
else:
    ...

работает так:

выход без break → else выполняется
выход через break → else не выполняется

С помощью while можно обходить объекты по индексам:

index = 0
items_length = len(items)

while index < items_length:
    print(
        items[index]
    )

    index += 1

В обратном направлении можно использовать как положительные, так и отрицательные индексы.

Функцию len() можно сохранить заранее:

items_length = len(items)

если длина объекта во время обхода не изменяется.