while, for — оператори циклів

Порядок дій алгоритму може мати цикли. Частину інструкцій потрібно повторювати знову і знову.

Цикл while

У загальному випадку оператор циклу while записується наступним чином:

while <умова>:
    <блок коду, якщо умова == True>

<наступні оператори>

Як інтерпретатор Python обробляє оператор циклу while?

  1. На першому кроці обчислюється значення <умова>.
  2. Якщо результат обчислення дорівнює True, то виконається блок коду, який слідує відразу після рядка while <умова>:.
  3. Якщо результат обчислення дорівнює False, то блок коду не виконується, та будуть виконані <наступні оператори>.

Часто блок коду у циклі while називається тілом циклу.

digraph While {
  node [shape=box fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];
  edge [fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];

  start     [shape=point label="попередні оператори"];

  subgraph cluster {
    style     = filled;
    color     = "#f9f9f9";
    label     = "Цикл";
    fontname  = "Helvetica"
    fontsize  = "10"
    labeljust = "l"

    check     [shape=diamond label="умова"];
    allow     [label="тіло циклу"];
  }

  end       [label="наступні оператори"];
  start -> check;
  check -> allow [label="True"];
  check -> end [label="False"];
  allow -> check;
}

Задача. Отримати суму всіх елементів масиву array = [7, 2, 5, 1, 0, 3, 10, 11, 3, 9].

Розв'язання задачі без циклів:

array: list[int] = [7, 2, 5, 1, 0, 3, 10, 11, 3, 9]
summa: int = array[0] + array[1] + array[2] + array[3] + \
           array[4] + array[5] + array[6] + array[7] + \
           array[8] + array[9]
print(summa)

Такий код буде працювати правильно (відповідь: 51 — легко перевірити на калькуляторі), але як буде виглядати код, якщо нам потрібно просумувати масив із 100 чисел? Масив із 10 000 чисел?

Це підходяща задача, щоб вирішити її за допомогою циклів — тому що нам потрібно операцію суми повторювати знову і знову.

array: list[int] = [7, 2, 5, 1, 0, 3, 10, 11, 3, 9]
index: int = 0
summa: int = 0
while index < 10:
    element: int = array[index]
    summa += element
    print(f"Додаємо елемент під індексом {index} = {element}. Проміжна сума = {summa}")
    index += 1
print("Підсумок:", summa)

Важливе в цій програмі:

  • змінна summa потрібна для того, щоб накопичувати проміжну суму елементів;
  • змінна index потрібна для того, щоб у циклі перебрати всі елементи масиву array за їхніми індексами: 0, 1 і так далі;
  • умова циклу: index < 10, тобто програма буде входити в цикл тоді, коли index = 0, 1, 2… 9 (включаючи 9), а для індексу 10 вже входити не буде;
  • у тілі циклу виконується сумування елемента під індексом index, значення index збільшується на +1;
  • як тільки index стане рівним 10, то цикл закінчується і виконується друк на екран суми.

Блок-схема алгоритму сумування з циклом показана на рисунку нижче:

digraph CFG {
  node [shape=box fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];
  edge [fontname="Helvetica" fontsize="12" color="#87D0F5" penwidth=2];

  start    [shape=oval label="Початок"];
  init1    [label="array = [7, 2, ..., 9]\nindex = 0\nsumma = 0"];

  subgraph cluster_0 {
    style     = filled;
    color     = "#f9f9f9";
    label     = "Цикл while";
    fontname  = "Helvetica"
    fontsize  = "10"
    labeljust="l"

    loop_cond [shape=diamond label="index < 10"];
    get_elem  [label="element = array[index]\nsumma += element\nindex += 1"];
  }

  final_print [shape=parallelogram label="summa"];
  end      [shape=oval label="Кінець"];

  start -> init1 ->  loop_cond;
  loop_cond -> get_elem [label="так"];
  get_elem -> loop_cond;
  loop_cond -> final_print [label="ні"];
  final_print -> end;
}

Нескінченний цикл

Цикл, в якому умова завжди дорівнює True, називається нескінченним циклом. Це суперечить поняттю алгоритму («кінцева сукупність точно заданих правил…»). Нескінченний цикл може викликати зависання програми (т. к. з нього може не бути виходу).

for — організація циклів по масивах, списках та рядках

Цикл for може перебрати всі елементи масиву, списку або рядка.
У загальному випадку цикл for записується так:

for <змінні> in <ітерабельне>:
     <складений оператор>

Ітерабельне може бути:

  • масиви (list або tuple), тоді в змінну циклу буде записано чергове значення масиву;
  • словник (dict), тоді в змінну циклу буде записано черговий ключ із словника;
  • рядок (str), тоді в змінну циклу буде записано черговий символ рядка;

Часто складений оператор у циклі for називають тілом циклу.

Задача. Вивести всі елементи масиву, помножені на два.

Програма нижче перебирає всі елементи масиву array і на кожній ітерації присвоює чергове значення змінній element. У тілі циклу оператор print друкує на екран вміст змінної element, помножене на 2:

array: list[int] = [5, 3, 10, 12, 7]
for element in array:
    print(element * 2)

Задача. Порахувати кількість голосних букв у слові.

Програма нижче перебирає всі символи в слові word і перевіряє, чи є чергова літера character буква голосною. Якщо так, то збільшує лічильник знайдених голосних count на +1.

word: str = "дезоксирибонуклеїнова"
count: int = 0
for character in word:
    if character in "аеєиіїоуюя":
        # character — голосна
        print(character)
        count += 1
print("Знайдено голосних букв:", count)

Важливе в цій програмі:

  • змінна count — це лічильник знайдених голосних букв. Спочатку лічильник дорівнює нулю;
  • тіло циклу for спрацює рівно 21 рази — за кількістю букв у рядку "дезоксирибонуклеїнова"
  • у змінній циклу character на кожній ітерації циклу буде записана чергова буква: д, е, з, о, к, … в, a.
  • якщо character — один символ із рядка "аеєиіїоуюя", то вираз character in "ауоиэыяюеё" дорівнює True;

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

break і continue — оператори переривання циклів

Іноді потрібно вийти з циклу, не чекаючи кінця ітерацій.

Оператор break — перериває виконання поточного циклу і виходить з нього.

Оператор continue — перериває виконання поточної ітерації циклу (залишок інструкцій у поточній ітерації циклу не виконуються) і переходить до наступної ітерації.

Задача. Знайти в масиві перший-ліпший елемент, який дорівнює нулю, і вивести його індекс.

array: list[int] = [10, 7, 3, 4, 0, 12, 13, 0, 5, 2]
index: int = 0
for number in array:
    print('Перевіряємо число', number, 'під індексом', index)
    if number == 0:
        print('СТОП! Індекс першого нульового елемента:', index)         
        # зупиняємо цикл, задача вирішена, далі немає сенсу перевіряти         
        break 
    index += 1

Важливе в цій програмі:

  • у змінну number будуть записані числа 10, 7, 3 і так далі;
  • змінна index — це лічильник ітерацій;
  • якщо number дорівнює 0, то виведемо на екран повідомлення СТОП! і перервемо виконання циклу оператором break. Наступні ітерації цикла виконуватись не будуть;
  • на кожній ітерації циклу збільшуємо змінну index на `+1.

return як оператор переривання циклу

return — завершує роботу поточної функції або методу. Може повертати значення з функції або методу. Якщо після return не вказано жодного виразу, то повертається значення None.

Зверніть увагу, що вивід на екран буде різний, якщо return знаходиться в тілі циклу:

def f1():
    l = [1,2,3]
    for n in l:
        print(n)
        return
f1()

та return знаходиться за межами циклу:

def f2():
    l = [1,2,3]
    for n in l:
        print(n)
    return
f2()