К содержанию

Модуль 3 · Урок 3.1

Цикл while и состояние программы

Повторение по условию, счётчик и накопитель, почему цикл даёт верный ответ, цифры числа, break и continue.

8 задач

В модуле «Условия» сумма и наибольшее четырёх чисел потребовали четырёх имён и трёх if. Для тысячи чисел так не напишешь. Цикл повторяет одни и те же строки, пока выполняется условие, — и одна короткая программа обрабатывает сколько угодно данных.

Начнём с простого счёта, научимся накапливать сумму, снимать цифры числа и останавливать цикл досрочно, а в конце решим сквозную задачу для любого количества чисел.

Цикл while

while повторяет блок, пока условие истинно. Перед каждым повторением он проверяет условие. Если оно истинно, выполняется тело цикла — блок с отступом, — и проверка начинается заново. Как только условие ложно, выполнение переходит к строке после цикла. Нажми «Запуск» и посмотри, как выполнение возвращается к строке while:

i = 1while i <= 4:    print(i)    i += 1
1 2 3 4

Одно выполнение тела называют итерацией. После четвёртой итерации i равно 5, проверка 5 <= 4 ложна, и цикл заканчивается. Если условие ложно с самого начала — например, при i = 10, — тело не выполнится ни разу.

Если забыть i += 1, условие будет истинным всегда — получится бесконечный цикл. Останови его красной кнопкой Stop в панели Run PyCharm или сочетанием CtrlC в терминале.

Счётчик и накопитель

Счётчик считает события, накопитель собирает результат. Найдём сумму чисел от 1 до 4. Нажми «Запуск» и пройди цикл по шагам:

i = 1total = 0while i <= 4:    total += i    i += 1print(total)
10

i — следующее число, которое нужно прибавить. total собирает сумму уже обработанных чисел; такая переменная называется накопителем. Переменную, которая считает события, называют счётчиком. Вот значения при каждой проверке условия:

Перед каждой проверкой в total лежит сумма чисел до i - 1: 0, 1, 1 + 2, 1 + 2 + 3, 1 + 2 + 3 + 4. Четыре проверки дают True и запускают тело, пятая — False, и цикл заканчивается.

Сумма начинается с 0: прибавление нуля не меняет результат. Произведение начинают с 1: если начать с нуля, оно навсегда останется нулём.

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

Цикл должен на каждой итерации приближаться к выходу. В сумме чисел i растёт на 1 и неизбежно превысит 4 — значит, цикл закончится. Прежде чем запускать свой цикл, ответь на два вопроса: что хранит каждая переменная перед проверкой — это видно по ленте проверок выше, — и почему условие когда-нибудь станет ложным.

Тонкости:инвариант цикла

Утверждение, которое верно перед каждой проверкой условия, называют инвариантом цикла. Для суммы это «total равен сумме чисел от 1 до i - 1». Перед первой проверкой оно верно: i = 1, сумма пустого набора — 0. Тело прибавляет i и увеличивает i, поэтому утверждение сохраняется. Когда цикл останавливается при i = 5, сложены ровно числа от 1 до 4. Инвариант — не команда Python, а способ доказать, что цикл считает верно.

Цифры числа

Цифры числа снимают по одной справа: % 10 берёт последнюю, // 10 её отбрасывает.

number = -5072n = abs(number)digit_sum = 0while n > 0:    digit = n % 10    digit_sum += digit    n //= 10print(digit_sum)
14

Это тот же накопитель, только складываются цифры. Проследи n и сумму по шагам:

  1. n = 5072: последняя цифра n % 10 = 2, n // 10 = 507.
  2. n = 507: последняя цифра n % 10 = 7, n // 10 = 50.
  3. n = 50: последняя цифра n % 10 = 0, n // 10 = 5.
  4. n = 5: последняя цифра n % 10 = 5, n // 10 = 0.
  5. n = 0 — цикл закончен. Сумма цифр 5072 равна 14.

Каждая итерация снимает последнюю цифру, и следующая видит соседнюю слева. number хранит исходное число, а n — рабочая копия, которую цикл уменьшает. Знак — не цифра, поэтому сначала берут модуль: abs(-5072) — 5072.

Для числа 0 цикл не выполнится ни разу. Сумма цифр 0 при этом верна, а вот количество цифр получится 0, хотя в записи одна цифра. Ноль при подсчёте цифр обрабатывают отдельно.

break и continue

break завершает цикл досрочно, continue пропускает остаток итерации. break сразу завершает цикл, в котором стоит. Это удобно, когда признак окончания становится известен внутри тела. Числа вводятся по одному, 0 — признак конца ввода:

total = 0while True:    n = int(input())    if n == 0:        break    total += nprint(total)
5↵ 7↵ 0↵ 12

while True сам по себе бесконечен: условие всегда истинно, а выход задаёт break. 0 здесь — только признак окончания, в сумму он не входит.

continue пропускает остаток тела и сразу переходит к следующей проверке условия. Сложим нечётные числа от 1 до 5 — пройди по шагам и посмотри, как чётные i перескакивают total += i:

i = 0total = 0while i < 6:    i += 1    if i % 2 == 0:        continue    total += iprint(total)
9

Увеличение i стоит первым, до continue. Если поставить i += 1 в конец тела, на первом же чётном числе continue перескочит его, и цикл никогда не закончится.

Первая степень

Цикл может искать первое значение, которое достигло границы. Найдём наименьшее целое k >= 0, для которого 2 ** k >= n:

n = 17k = 0power = 1while power < n:    power *= 2    k += 1print(k)
5

Перед каждой проверкой power — это 2 в степени k. Цикл прекращается при первом достижении границы: 2⁴ = 16 ещё меньше 17, а 2⁵ = 32 уже нет. Для n = 1 ответ 0 получается без единой итерации.

Сквозная задача

Сквозная задача курса: цикл заменяет повторяющиеся if. В уроке о ветвлении сумма и наибольшее из 5, −2, 10, 7 потребовали четырёх имён и трёх if. С while числа можно вводить по одному до признака окончания 0, и программа не зависит от их количества:

n = int(input())total = 0best = nwhile n != 0:    total += n    if n > best:        best = n    n = int(input())print(total, best)
5↵ -2↵ 10↵ 7↵ 0↵ 20 10

Первое число читается до цикла: с него начинается best, как в уроке о ветвлении, и его же проверяет условие n != 0. Каждое следующее число читается в конце тела — чтобы проверка увидела его до того, как оно попадёт в сумму. total — накопитель, а три if прошлого урока стали одним if внутри цикла.

Итог

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

  • whileПроверяет условие перед каждой итерацией; ложное сразу условие — ни одной итерации.
  • Накопитель и счётчикСумму и счётчик начинают с 0, произведение — с 1.
  • Выход из циклаКаждая итерация должна приближать условие к ложному; иначе — бесконечный цикл (Stop в PyCharm, CtrlC в терминале).
  • Цифры числаn % 10 — последняя цифра, n //= 10 отбрасывает её; сначала abs, ноль — отдельно.
  • breakСразу завершает цикл, в котором стоит.
  • continueПропускает остаток тела; изменение переменной условия ставят до него.
  • Признак окончанияПервое число читают до цикла, следующее — в конце тела; признак (0) в результат не входит.

Проверьте себя

Ответь сначала сам, потом открой ответ.

Вопрос 1

Сколько раз выполнится тело цикла while i < 5:, если перед ним i = 10?

ОтветСкрыть ответ
Ответ

Ни разу: первая же проверка 10 < 5 ложна.

Вопрос 2

Что напечатает программа?

i = 1product = 1while i <= 4:    product *= i    i += 1print(product)
ОтветСкрыть ответ
Ответ

24 = 1 · 2 · 3 · 4. Произведение начинается с 1: с нулём ответ был бы 0.

Вопрос 3

Почему цикл while n != 0: n //= 10 никогда не закончится при n = -15?

ОтветСкрыть ответ
Ответ

-15 // 10 даёт −2, затем −1, а -1 // 10 снова −1: ноль не достигается. Поэтому сначала берут модуль.

Вопрос 4

Чем опасен такой цикл?

i = 0while i < 5:    if i == 2:        continue    i += 1
ОтветСкрыть ответ
Ответ

При i == 2 continue перескакивает i += 1: i навсегда остаётся 2, и цикл бесконечен.

Вопрос 5

Программа из урока складывает числа до признака 0 с break. Что она напечатает, если ввести 3, 8, 0, 5?

ОтветСкрыть ответ
Ответ

11: после 0 цикл закончен, и 5 программа уже не читает.

Практика

Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.

Наименьшее k, для которого 2 ** k >= n

Программа ищет наименьшее k, для которого 2 ** k >= n. Запусти её дважды — введи 1, затем 64 — и запиши оба ответа.

n = int(input())k = 0power = 1while power < n:    power *= 2    k += 1print(k)

Запишите два числа через пробел: для n = 1, затем для n = 64.

Что напечатает программа?

i = 1total = 0while i <= 5:    total += i * i    i += 1print(total)

Введите число.

Что напечатает программа?

i = 10count = 0while i > 0:    i -= 3    count += 1print(count, i)

Запишите напечатанные числа через пробел в порядке вывода.

Напиши программу: произведение чисел от 1 до 5

Напиши программу, которая циклом while находит произведение чисел от 1 до 5. Запусти её, затем поменяй начальное значение произведения с 1 на 0 и запусти снова. Запиши оба результата.

Запишите два числа через пробел: с началом 1, затем с началом 0.

Напиши программу: сумма и количество цифр

Напиши программу, которая циклом while n > 0 находит сумму и количество цифр числа. Запусти её для 90817, затем для 0.

Запишите три числа через пробел: сумма цифр 90817, количество его цифр, затем количество цифр, которое тот же цикл насчитает для 0.

Напиши программу: количество и сумма до нуля

Напиши программу: числа вводятся по одному, ввод заканчивается нулём. Программа печатает количество и сумму введённых чисел без нуля. Запусти её и введи 4, −2, 9, 0.

Запишите два числа через пробел: количество, затем сумму.

Напиши программу: сколько шагов до 1

Пока число не равно 1, чётное делят пополам, а нечётное заменяют на 3n + 1. Напиши программу, которая считает шаги до 1, и запусти её для 6 и для 27.

Запишите два числа через пробел: шаги для 6, затем для 27.

Напиши программу: цифры числа в обратном порядке

Напиши программу, которая переворачивает цифры числа: из 123 получает 321. Запусти её для 1230 и запиши, что она напечатала.

Введите число.