Part 3

Циклы с условиями

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

# Print numbers until the variable a equals 5
a = 1
while True:
    print(a)
    a += 1
    if a == 5:
        break
Пример вывода

1 2 3 4

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

while <condition>:
    <block>

Идея состоит в том, что выполнение снова и снова возвращается к проверке условия: если условие истинно, выполняется код внутри блока. Если в какой-то момент условие становится ложным, выполнение программы продолжается со строки после блока while.

3 1 1

В следующем цикле условие - number < 10. Блок внутри цикла выполняется только если переменная number меньше 10.

number = int(input("Please type in a number: "))

while number < 10:
    print(number)
    number += 1

print("Execution finished.")

Это могло бы вывести:

Пример вывода

Please type in a number: 4 4 5 6 7 8 9 Execution finished.

В этой структуре условие всегда проверяется до выполнения блока внутри цикла. Может случиться так, что блок вообще ни разу не выполнится:

Пример вывода

Please type in a number: 12 Execution finished.

12 не меньше 10, поэтому программа не выводит ни одного числа.

Инициализация, условие и обновление

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

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

3 1 2

Если отсутствует любой из этих трех компонентов, цикл, скорее всего, не будет работать правильно. Типичная ошибка - пропустить шаг обновления:

number = 1

while number < 10:
    print(number)

print("Execution finished.")

Здесь значение переменной number никогда не меняется. Программа застревает в бесконечном цикле, и один и тот же фрагмент кода повторяется снова и снова, пока пользователь не остановит выполнение, например нажав Control + C:

Пример вывода

1 1 1 1 1 (continued ad infinitum...)

Запись условий

Любое булево выражение или их комбинация является допустимым условием в цикле. Например, следующая программа выводит каждое третье число, но только пока число меньше 100 и не делится на 5:

number = int(input("Please type in a number: "))

while number < 100 and number % 5 != 0:
    print(number)
    number += 3

Два примера выполнения программы с разными входными данными:

Пример вывода

Please type in a number: 28 28 31 34 37

Пример вывода

Please type in a number: 96 96 99

Когда введено 28, цикл заканчивается на числе 37, потому что следующее число - 40, а оно делится на 5. Когда введено 96, цикл заканчивается на числе 99, потому что следующее число - 102, а оно не меньше 100.

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

number = int(input("Please type in a number: "))

while number != 10:
    print(number)
    number += 2

Если введено четное число, равное 10 или меньше, цикл завершится:

Пример вывода

Please type in a number: 4 4 6 8

Во всех остальных случаях цикл выполняется бесконечно, потому что переменная уже никак не сможет стать равной 10. Например, входные значения 3 или 12 привели бы к бесконечному циклу.

Советы по отладке

Представьте, что вы пишете немного более сложную программу, например из следующего упражнения, Powers of two. Первые попытки могут выглядеть так:

limit = int(input("Upper limit:"))
number = 1
while number == limit:
   # more code

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

Скорее всего, с первой попытки код не будет работать так, как нужно. Возможно, его придется тестировать десятки или даже сотни раз, прежде чем он заработает правильно.

Этот фрагмент кода всегда запрашивает ввод у пользователя, что делает тестирование медленным и неудобным. При каждом тестировании программы нужно вводить данные.

Один способ обойти это - "зашить" входное значение в код на время тестирования:

# let's hard-code the input value for testing
limit = 8 # int(input("Upper limit"))
number = 1
while number == limit:
   # more code 

Когда программа работает с одним зашитым входным значением, ее легко протестировать и с другими зашитыми значениями. Когда кажется, что она работает правильно во всех случаях, ее можно протестировать с вводом от пользователя.

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

# the test said the program works incorrectly when the input is 42
limit = 42 # int(input("Upper limit"))
number = 1
while number == limit:
   # more code

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

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

Помимо команд вывода, для отладки можно использовать много других инструментов. Один из них - инструмент визуализации на сайте Python Tutor. Этот инструмент позволяет выполнять код строка за строкой, а также показывает значения, сохраненные в переменных на каждом шаге.

Немного сломанный код из примера отладки в предыдущем разделе визуализирован в Python Tutor на следующем изображении:

3 1 3

Красная стрелка показывает, где сейчас находится выполнение программы. Инструмент отображает то, что уже было выведено, а также показывает значение каждой переменной на каждом шаге. Выполнение продвигается вперед строка за строкой, когда вы нажимаете Next.

Чтобы воспользоваться инструментом визуализации, достаточно скопировать свой код и вставить его в окно кода инструмента. У инструмента есть некоторые ограничения по сравнению с версией Python, используемой в этом курсе. Если вы столкнетесь с непонятными сообщениями об ошибках, возможно, лучше попробовать другой метод отладки.

Более опытные программисты редко активно пользуются инструментом визуализации, но для новичка он может быть ценной помощью. В программировании как дисциплине почти нет места удаче или случайности. Важно, чтобы программист понимал, какие значения создаются его кодом в любой конкретный момент выполнения. Если значения, сохраненные в переменных, не такие, как ожидалось, в программе, скорее всего, есть ошибка.

Инструмент визуализации и отладочные команды вывода - два отличных способа для программиста увидеть собственными глазами, что программа делает именно то, что от нее ожидалось.

Построение строк

В самую первую неделю курса мы узнали, что строки можно "строить" из более коротких строк с помощью оператора +. Например, это корректный код Python:

words = "pride"
words = words + ", prejudice"
words = words + " and python"

print(words)
Пример вывода

pride, prejudice and python

Оператор += позволяет записать это немного компактнее:

words = "pride"
words += ", prejudice"
words += " and python"

print(words)

Это также относится к f-строкам, что может пригодиться, если значения, сохраненные в переменных, нужны как части итоговой строки. Например, это сработает:

course = "Introduction to Programming"
grade = 4

verdict = "You have received "
verdict += f"the grade {grade} "
verdict += f"from the course {course}"

print(verdict)
Пример вывода

You have received the grade 4 from the course Introduction to Programming

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

Точно такая же идея применима и к строкам: внутри цикла можно добавлять к строке новые части. Этот прием должен пригодиться в следующем упражнении.

Вы дошли до конца этого раздела! Перейти к следующему разделу:

Текущие баллы можно посмотреть в синем индикаторе в правом нижнем углу страницы.