Больше не нужно искать работу мечты — присоединяйтесь к команде Клауда

Цикл while в Python: руководство

Роман Андреев
Роман Андреев
Технический писатель
03 октября 2022 г.
1332
10 минут чтения
Средний рейтинг статьи: 5

В статье расскажем об особенностях работы циклов while в Python и разберем проблемы, которые возникают у начинающих «питонистов».

Для чего нужен и как работает оператор while

Циклические конструкции в языках программирования используются для повторения отдельных блоков кода до тех пор, пока не будет выполнено определенное условие. Одним из таких инструментов в Питоне является конструкция while. Понять работу цикла while в Python 3 нетрудно: просто переведите это слово с английского, как «до тех пор, пока». Пример кода:

number = 0
while number < 3:
    print('Условие истинно, переменная number меньше трех и сейчас равна', number, ', поэтому цикл продолжает выполняться.')
    number += 1
print('Мы вышли из цикла, так как значение переменной number стало равным', number, ', а условие перестало быть истинным.')
input('Нажмите Enter для выхода')

Запустив эту программу, получим вполне наглядный вывод:

Условие истинно, переменная number меньше трех и сейчас равна 0 , поэтому цикл продолжает выполняться.

Мы вышли из цикла, так как значение переменной number стало равным 3 , а условие перестало быть истинным.

А вот пример части вполне реальной программы:

while score1 < 5 and score2 < 5:
    print('Игра продолжается, так как никто не набрал 5 очков.')

Если буквально переводить с Python на русский (а начинающим так делать полезно), то инструкция программы такая: до тех пор, пока количество очков первого игрока (score1) или количество очков второго игрока (score2) меньше 5, выводить на экран сообщение «Игра продолжается, так как никто не набрал 5 очков».

Интерпретатор рассматривает условие while (в данном случае: score1 < 5 and score2 < 5) как истинное, True, и перейдет к следующему блоку кода только тогда, когда оно станет ложным, False (то есть один из игроков наберет 5 очков, и игра закончится). Чтобы было понятнее, давайте взглянем на эту простую программу для игры в кости и рассмотрим, как она работает:

import random

score1 = 0
score2 = 0
die1 = 0
die2 = 0

input('Первый игрок бросает кубик, нажмите Enter!\n')

while score1 < 5 and score2 < 5:

    die1 = random.randint(1, 6)
    print(die1,'\n')
    input('Теперь бросает кубик второй игрок, нажмите Enter!\n')

    die2 = random.randint(1, 6)
    print(die2,'\n')

    if die1 > die2:
        score1 += 1
    elif die1 < die2:
        score2 += 1
    else:
        print('Ничья\n')
    print('Счёт', score1, ':', score2,'\n')
    input('Нажмите Enter!\n')

if score1 > score2:
    input('Победил первый игрок! Нажмите Enter для выхода')
else:
    input('Победил второй игрок! Нажмите Enter для выхода')

Для получения случайных значений при броске кубиков нам понадобится функция random, поэтому сначала вызываем ее, а затем создаем переменные для подсчета выигранных каждым игроком партий и для результатов бросков кубика. А все броски будут выполняться внутри блока с таким условием:

while score1 < 5 and score2 < 5:

Это означает: до тех пор, пока количество выигранных партий первым и вторым игроком не достигнет пяти, игра не прекратится. Обратите внимание, что для создания условия мы использовали логический оператор and: это обеспечит выход из игры, как только значение одной из переменных (score1 или score2) достигнет пяти (в случае с or выход произошел бы только при выполнении обоих условий).

Дальше выполняются броски: они имитируются нажатием на Enter и присвоением случайных значений переменным die1 и die2. Затем эти переменные сравниваются, и в результате сравнения очко присуждается первому или второму игроку, а в случае ничьей партия переигрывается.

Вы, наверное, заметили, что у этой программы есть один недостаток — теоретически генератор случайных чисел может выдавать большое число ничьих, в результате чего игрокам придется нажимать клавиши снова и снова. То есть получится некое подобие бесконечного цикла, а значит нужно исправить программу так, чтобы количество итераций (повторений блока кода) было ограничено. Одно из решений: ввести дополнительную переменную, принимающую количество сыгранных партий. А мы как раз рассмотрим методы борьбы с настоящими бесконечными циклами.

Бесконечные циклы и борьба с ними

Это одна из главных проблем программистов. Зацикливание программ приводит к переполнению оперативной памяти или перегрузке процессорных мощностей, что чревато вылетами приложений или зависанием операционной системы. Понять, что такое бесконечный цикл, вам поможет эта маленькая программа:

number = 1
while number > 0:
    print(number)
    number += 1

Запустите ее в интерпретаторе Python и посмотрите на результат. Числа будут выводиться бесконечно (на практике — до того момента, пока у компьютера не закончится свободная память). Теперь убьем программу, закрыв IDE, и разберем, что же здесь случилось:

number = 1

Вводим переменную number и задаем ей значение.

while number > 0:
    print(number)
    number += 1

Создаем условие: до тех пор, пока число больше нуля, печатать значение и увеличивать его на единицу. Нетрудно догадаться, что условие всегда будет оставаться истинным, потому что все новые числа будут больше нуля, а значит, программа никогда не прекратит работу. Можно вызвать бесконечный вывод и так:

number = 1
while number == 1:
    print(number)

Но одно дело создать такую ситуацию искусственно, однако чаще всего бесконечные циклы создаются случайно, потому что программисты их не предусмотрели:

import random
fuel = 30
cities = 0
consumption = random.randint(1, 10)
while fuel != 0:
    cities += 1
    fuel -= consumption
    consumption = random.randint(1, 10)
    print('Вы проехали',cities,'городов')
input('Топливо закончилось, нажмите Enter для выхода из машины')

Наша цель — объехать как можно больше городов, пока не закончится топливо. Однако мы объехали уже несколько сотен городов и спокойно едем дальше:


Вы проехали 298 городов
Вы проехали 299 городов
Вы проехали 300 городов
...

Разбираемся, что здесь не так. Для этого слегка перепишем предпоследнюю строчку:

print('Вы проехали',cities,'городов, и у вас осталось в баке',fuel,'литров')

Вы проехали 6 городов, и у вас осталось в баке 5 литров
Вы проехали 7 городов, и у вас осталось в баке -4 литров
Вы проехали 8 городов, и у вас осталось в баке -8 литров

Проблема найдена: в условиях у нас было выставлено while fuel != 0, однако переменная fuel так и не приняла значения 0 (если бы это случилось волею рандома, программа бы завершилась), а ее значение сразу стало отрицательным. Так как количество топлива в баке не было равным нулю, условие осталось истинным, и программа продолжила выполнение дальше. Осталось изменить всего лишь один знак в строке условия, и всё заработает как надо:

import random
fuel = 30
cities = 0
consumption = random.randint(1, 10)
while fuel > 0:
    cities += 1
    fuel -= consumption
    consumption = random.randint(1, 10)
    print('Вы проехали',cities,'городов')
input('Топливо закончилось, нажмите Enter для выхода из машины')

Теперь условие будет истинно только до того момента, пока fuel будет больше нуля. Вот что у нас получилось в итоге:

Вы проехали 5 городов
Топливо закончилось, нажмите Enter для выхода из машины

Условие цикла while оказалось выполненным, и программа перешла к следующему блоку.

Пишем программу с while и ветвлениями

Ветвления реализуются с помощью условных операторов if-elif-else, а в сочетании с циклами делают программы очень разнообразными. Давайте напишем несложный спортивный симулятор. Представим, что в очередном финале хоккейного Кубка Гагарина встретились СКА и ЦСКА. Основное время не выявило победителя, поэтому игра продолжилась до первой заброшенной шайбы:

import random

goal1 = 0
goal2 = 0
time = 1

while goal1 == 0 and goal2 == 0:    
    attack = random.randint(1, 2)
    if attack == 1:
        shoot = random.randint(1, 2)
        if shoot == 1:
            keeper = random.randint(1, 2)
            if keeper == 1:
                print('Шайба отбита вратарём ЦСКА, матч продолжается')
                time += 1
                attack = random.randint(1, 2)
            else:
                print('Гооол! СКА побеждает 1:0!')
                goal1 += 1
        else:
            print('Нападающий СКА пробил мимо ворот')
            time += 1
            attack = random.randint(1, 2)
    else:
        shoot = random.randint(1, 2)
        if shoot == 1:
            keeper = random.randint(1, 2)
            if keeper == 1:
                print('Шайба отбита вратарём СКА, матч продолжается')
                time += 1
                attack = random.randint(1, 2)
            else:
                print('Гооол! ЦСКА побеждает 0:1!')
                goal2 += 1
        else:
            print('Нападающий ЦСКА пробил мимо ворот')
            time += 1
            attack = random.randint(1, 2)

print('Матч окончен на', time, 'минуте дополнительного времени.')
input()

Как видите, while здесь выполняет ключевую функцию, обеспечивая выход при выполнении главного условия. Кстати, цикл этот теоретически бесконечный, хотя представить, что генератор случайных чисел всё время будет выбирать «неголевые» числа, сложно. Тем не менее полезно ограничить матч. Подумайте, как это можно сделать (подсказка: добавить условие для переменной time, установив максимальное количество минут).

А у нас первый овертайм получился напряженным, соперники по четыре раза пытались поразить ворота друг друга, и в итоге это удалось москвичам:

Нападающий СКА пробил мимо ворот
Шайба отбита вратарём СКА, матч продолжается
Шайба отбита вратарём ЦСКА, матч продолжается
Нападающий СКА пробил мимо ворот
Нападающий ЦСКА пробил мимо ворот
Шайба отбита вратарём ЦСКА, матч продолжается
Шайба отбита вратарём СКА, матч продолжается
Шайба отбита вратарём СКА, матч продолжается
Гооол! ЦСКА побеждает 0:1!
Матч окончен на 9 минуте дополнительного времени.

Примерно так устроены все спортивные менеджеры и симуляторы — с той разницей, конечно, что на результат там влияет множество факторов. А принцип работы любых сложных программ одинаков: всё организуется при помощи циклов, условий и интерактивных элементов, один из которых — функция input().

Операторы прерывания цикла

«Верными помощниками» while являются операторы break и continue, без которых код многих программ был бы не таким удобным. break завершает цикл досрочно при выполнении некоторого условия, а continue игнорирует определенные итерации. Эти операторы позволяют значительно улучшить программу, при этом их синтаксис прост. Вот пример изящного решения с break и continue для обработки ошибок без вылета приложения на рабочий стол:

while True:
    try:
        number = int(input('Введите число: '))
        break
    except ValueError:
        print('Вы напечатали что-то другое')
        continue
print('Спасибо!')

При вводе некорректных значений (букв и специальных символов, которые нельзя преобразовать в целые числа) программа с этим кодом не будет вылетать, а будет терпеливо предлагать пользователю ввести число. Реализуется это при помощи конструкции try-except, а также операторов break и continue. При успешном преобразовании символа в целое число программа сразу завершит цикл благодаря break, а неправильный ввод проигнорирует и запустит новую итерацию благодаря continue.

Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
03 октября 2022 г.
1332
10 минут чтения
Средний рейтинг статьи: 5
Пока нет комментариев