Към съдържанието
wannacode

Цикли

Проблем

Колко ще спестиш?

Решаваш да спестяваш: първия месец отделяш 10 €, втория 20 €, третия 30 € и все така с по 10 € повече. Колко ще имаш след 4 месеца?

total = 0
total += 1 * 10
total += 2 * 10
total += 3 * 10
total += 4 * 10
print(total)
Изход
100

Работи. Но след 3 години ще са 36 реда, почти еднакви. А ако броят на месеците се въвежда от клавиатурата, изобщо не знаеш колко реда да напишеш. Трябва ти начин да кажеш „повтори това толкова пъти“.

Идеята

for: повтори за всяко число

Повтарящото се парче код се казва цикъл. Най-често ползваният е for. Ето числата от 1 до 10:

for i in range(1, 11):
print(i)
Изход
1
2
3
4
5
6
7
8
9
10

for i in range(1, 11): значи „за всяко i от числата, които дава range“. i е броячът: при всеки кръг в него се записва следващото число. range има три части, разделени със запетая:

  • Начало: 1. Първото число. Ако го няма, range(10), началото е 0.
  • Край: 11. Краят не влиза: последното число е 10. Затова range(1, 11) е от 1 до 10.
  • Стъпка: колко се добавя всеки път. Ако я няма, е 1. range(3, 0, -1) брои назад: 3, 2, 1.

Тялото е отместеното с 4 интервала след двоеточието, както при if.

Всяко изпълнение на тялото се казва итерация или просто кръг.

По-точно, за любопитните
  • Стъпката може да е каквато ти трябва: през едно, назад. А range(10) брои от 0 до 9: пак 10 кръга. Защо се брои от 0, ще стане ясно в урока за списъците.
for i in range(1, 11, 2):
print(i, end=" ")
print()
for i in range(10, 0, -1):
print(i, end=" ")
print()
for i in range(10):
print(i, end=" ")
print()
Изход
1 3 5 7 9
10 9 8 7 6 5 4 3 2 1
0 1 2 3 4 5 6 7 8 9
  • В Python броячът остава и след цикъла, с последната си стойност. В Java, C# и JavaScript го няма след цикъла.
for i in range(1, 4):
print(i)
print("След цикъла i е", i)
Изход
1
2
3
След цикъла i е 3
  • Python няма for с условие и стъпка като for (int i = 1; i <= 10; i++) в Java. Когато трябва „докато нещо е вярно“, има while (след малко).

Виж го

Кръг по кръг

Това са спестяванията от първата карта, с цикъл. Следи как се сменят month и total.

total = 0
for month in range(1, 5):
total += month * 10
print(total) # 100
Стъпка по стъпка, с думи
  1. total започва от 0.
  2. month = 1, първото число от range(1, 5). Влизаме в тялото.
  3. Кръг 1: total += 1 * 10, total става 10.
  4. month става 2, следващото число от range. Още един кръг, total става 30.
  5. month 3: total става 60.
  6. month 4: total става 100.
  7. range(1, 5) няма повече числа: краят 5 не влиза. Цикълът свършва, month остава 4.
  8. След цикъла total е 100.

Тялото е един ред и е написано веднъж. За 36 месеца сменяш само 5 на 37. А можеш да сложиш там и променлива, прочетена от клавиатурата.

Пробвай

Обратно броене

Какво ще отпечата програмата?

for sec in range(3, 0, -1):
print(sec)
print("Старт!")
Отговор

Идеята

while: докато не дойде краят

Понякога не знаеш предварително колко кръга ще има. Касата чете цени, докато касиерът не въведе 0, и тогава казва сметката. Тук for не пасва. Пасва while: повтаря, докато условието е вярно.

total = 0
price = int(input())
while price != 0:
total += price
price = int(input())
print(f"Общо: {total} €")
Вход
12
4
7
0
Изход
Общо: 23 €

Първата цена се чете преди цикъла, за да има какво да провери условието. Следващата се чете в края на тялото. Ако първото число е 0, тялото не се изпълнява нито веднъж.

Понякога тялото трябва да се изпълни поне веднъж, а условието да се провери след кръга. Например въпрос, който се повтаря, докато отговорът не стане приемлив. В Java, C# и JavaScript за това има do-while. В Python го няма. Пише се while True:, цикъл, чието условие е винаги вярно, и вътре break, който го спира, щом отговорът е добър (за break още след малко):

while True:
print("Колко билета (от 1 до 10)?")
count = int(input())
if 1 <= count <= 10:
break
print(f"Запазени билети: {count}")
Вход
0
15
3
Изход
Колко билета (от 1 до 10)?
Колко билета (от 1 до 10)?
Колко билета (от 1 до 10)?
Запазени билети: 3
По-точно, за любопитните
  • Ако условието никога не стане невярно, цикълът не свършва. Това е безкраен цикъл: програмата „увисва“ и трябва да я спреш ръчно. Най-честата причина е забравена промяна на променливата в условието, например липсващо price = … в края на тялото.
  • while True: без break вътре е безкраен цикъл. Провери, че има път до break.
  • Всеки for може да се напише като while. Избираш този, който се чете по-ясно: for за известен брой кръгове, while за „докато нещо стане“.

Пробвай

Намери грешката

Програмата трябва да събере числата от 1 до 5: 1 + 2 + 3 + 4 + 5 = 15. Отпечатва 10. На кой ред е грешката?

Избери реда с грешката.

Сумата е в total, не в sum: в Python sum е име на вградена функция и е добре да не го заемаш.

Идеята

break и continue

Две думи сменят обичайния ход на цикъла.

continue прескача останалото от текущия кръг и минава на следващия. Записваш часове за прегледи от 9 до 17, но в 13 е обедната почивка:

for hour in range(9, 18):
if hour == 13:
continue
print(f"{hour}:00")
Изход
9:00
10:00
11:00
12:00
14:00
15:00
16:00
17:00

break спира целия цикъл веднага. Търсиш първото число, на което 91 се дели. Щом го намериш, няма смисъл да продължаваш:

n = 91
for d in range(2, n):
if n % d == 0:
print(f"{n} се дели на {d}")
break
Изход
91 се дели на 7
По-точно, за любопитните
  • break спира само цикъла, в който се намира. Ако е във вложен цикъл (следващата карта), външният продължава.
  • while True: с break вътре вече го видя: цикъл, който свършва не от условието, а от break на подходящото място.

Идеята

Цикъл в цикъл

Залата на киното има 3 реда по 4 места. Искаш да отпечаташ всички места. За всеки ред минаваш през всички места в него:

for row in range(1, 4):
for seat in range(1, 5):
print(f"[{row}-{seat}]", end="")
print()
Изход
[1-1][1-2][1-3][1-4]
[2-1][2-2][2-3][2-4]
[3-1][3-2][3-3][3-4]

Това се казва вложени цикли. Вътрешният цикъл минава целия си път при всеки кръг на външния: 3 реда · 4 места = 12 отпечатвания. end="" казва на print да не слиза на нов ред, затова местата остават на един ред. Празното print() след вътрешния цикъл слиза на нов ред.

Пробвай

Стълбичка

На първия ред трябва да има една звездичка, на втория две, на четвъртия четири. Какво трябва да пише на празното място?

for row in range(1, 5):
    for star in range():
        print("*", end="")
    print()

Идеята

Случайни числа за игрите

За игра на зарове трябва число, което програмата не знае предварително. Дава го random:

import random
dice = random.randint(1, 6)
print(f"Хвърли {dice}")

random е модул: готов код, който идва с Python. Включваш го с import random най-горе във файла, както math.

random.randint(1, 6) дава цяло число от 1 до 6. Внимавай: тук и двете граници влизат, за разлика от range.

Всяко пускане дава различно число, затова тук няма изход. Ето и цикъл, който хвърля, докато не се падне шестица:

import random
rolls = 0
while True:
dice = random.randint(1, 6)
rolls += 1
if dice == 6:
break
print(f"Шестица след {rolls} хвърляния")
По-точно, за любопитните
  • Ако зададеш начално число с random.seed(42), всяко пускане дава една и съща поредица. Това помага при тестване.
  • random.random() дава дробно число от 0 до 1 (без 1), като Math.random() в JavaScript.
  • Числата не са истински случайни: смятат се по формула. За игри стигат, за пароли и сигурност не.

Упражнение

Задачи с цикли

Реши задачите в редактора си. За всяка има примерен вход и изход, с който да сравниш своя. Числото се чете както в урока „Вход и изход“.

1. Таблица за умножение. Прочети число и отпечатай произведенията му с числата от 1 до 10.

Вход
7
Изход
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70

2. Просто число. Едно число е просто, ако се дели само на 1 и на себе си: 2, 3, 5, 7, 11… Прочети число и кажи дали е просто. Подсказка: опитай делителите от 2 нагоре и спри с break при първия.

Вход
91
Изход
91 не е просто

За 11 изходът е „11 е просто“.

3. Цифрите на число. Прочети цяло положително число. Отпечатай го наобратно и сумата на цифрите му. Подсказка: n % 10 е последната цифра, а n // 10 маха последната цифра. Повтаряй, докато числото не стане 0.

Вход
2024
Изход
Обратно: 4202
Сума на цифрите: 8

4. Познай числото. Компютърът „намисля“ число от 1 до 100, а ти го търсиш. След всеки опит програмата казва „По-малко е.“ или „По-голямо е.“, а накрая колко опита ти е отнело. Първо го напиши с тайно число 37, за да провериш с примера:

Вход
50
25
37
Изход
По-малко е.
По-голямо е.
Позна от 3 опита!

Когато работи, смени 37 със случайно число от 1 до 100. Вече и ти не знаеш отговора.

Още задачи

  • От 1 до N. Прочети N и отпечатай числата от 1 до N на един ред. За 5: 1 2 3 4 5.
  • Факториел. N! = 1 · 2 · 3 · … · N. За 5: 120. В Python цялото число няма горна граница: 20! е 2432902008176640000, а 30! се смята също толкова точно.
  • Прости числа до N. Отпечатай всички прости числа до N. За 20: 2 3 5 7 11 13 17 19. Проверката от задача 2 отива вътре в цикъл по числата: вложени цикли.
  • Фибоначи. Всяко число е сумата на предишните две: 0, 1, 1, 2, 3, 5, 8… Прочети N и отпечатай първите N числа. За 10: 0 1 1 2 3 5 8 13 21 34.
  • Квадрат от звездички. Прочети N и отпечатай квадрат N × N. За 3:
Изход
* * *
* * *
* * *
  • Триъгълник от звездички. Същото, но на всеки ред толкова звездички, колкото е номерът му. За 3:
Изход
*
* *
* * *
  • Хвърляне на монета. Прочети N, хвърли монета N пъти със случайно число (0 е ези, 1 е тура) и отпечатай колко пъти се е паднало всяко. Колкото по-голямо е N, толкова по-близо са двете числа до N / 2.
  • Камък, ножица, хартия. Играч срещу компютър. Играчът въвежда избора си, компютърът избира случайно, програмата казва кой печели. С while True и break пита „Още една игра? (да/не)“ и накрая отпечатва резултата.

Тест

Провери се

1. Колко пъти се изпълнява тялото на for i in range(5):?
2. Python няма do-while. Как се пише цикъл, чието тяло се изпълнява поне веднъж?
3. Какво прави continue?
4. Външният цикъл се върти 3 пъти, вътрешният 4 пъти. Колко пъти се изпълнява тялото на вътрешния?
5. Кой ред дава случайно число от 1 до 6?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·