+--------------------------+
|.------------------------.|
|| kee_reel@blog:~$ cd    ||
|| си python терминал     ||
|| opengl sql             ||
||                        ||
||                обо_мне ||
|.------------------------.|
+-::--------------------::-+
.--------------------------.
 // /ooooooooooooooooooooo\\ \\ 
 // /ooooooooooooooooooooooo\\ \\ 
//------------------------------\\
\\------------------------------//

Python. Циклы

Цикл (loop) – это механизм, позволяющий описать выполнение множества одинаковых действий.

Есть две разновидности циклов:

  • for
  • while

Цикл for

Вот пример определения цикла for:

some_list = [1, 2, 3, 4, 5, 0]
# Читается как: для каждого значения value в some_list выполнить
for value in some_list:
	# value это временная переменная, которая создаётся при входе в цикл
	# Ты можешь назвать её как угодно, не обязательно value -- например, если бы список назывался students, то я бы назвал переменную student
	# В эту переменную по очереди забираются значения из списка some_list
	print(value)
# Вывод:
# 1
# 2
# 3
# 4
# 5
# 0

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

some_dict = {
	1: 2,
	3: 4,
	5: 6
}
for key in some_dict:
	print(key)
# Вывод:
# 1
# 3
# 5

Чтобы пройти по значениям словаря, надо у словаря вызвать функцию values() (мы её упоминали в статье про контейнеры):

some_dict = {
	1: 2,
	3: 4,
	5: 6
}
for value in some_dict.values():
	print(value)
# Вывод:
# 2
# 4
# 6

Также можно пройтись сразу по парам ключ-значение через функцию items() (её тоже упомянали):

some_dict = {
	1: (1, 2),
	3: (3, 4),
	5: (5, 6)
}
for key, value in some_dict.items():
	print(key, value)
# Вывод:
# 1 (1, 2)
# 3 (3, 4)
# 5 (5, 6)

Обрати внимание, что мы получаем сразу две переменных – key и value. Помнишь, я говорил что items() возвращает список, содержащий кортежи из двух элементов – ключа и значения? То, что здесь происходит, называется распаковкой.

Распаковка

Распаковка – это разложение контейнера на составляющие элементы. Пример:

# Вот наш контейнер:
some_tuple = (1, 2, 3)
# Мы можем его распаковать в три переменных:
value_1, value_2, value_3 = some_list

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

Если бы мы объявили больше или меньше переменных, чем находится в контейнере:

value_1, value_2 = some_list # Ошибка, не надо так

то мы получили бы ошибку.

Распаковка довольно часто используется в циклах и вообще в коде. Посмотри как код выглядит без распаковки:

# Обработка словаря через цикл:
some_dict = {
	1: (1, 2, 3),
	2: (3, 4, 5),
	3: (5, 6, 7)
for value in some_dict.values():
	print(value[0], value[1], value[2])
# Обработка значений кортежа:
some_tuple = ('A', 'B', 'C')
print(some_tuple[0], some_tuple[1], some_tuple[2])
# Вывод:
1 2 3
3 4 5
4 5 6
A B C

И с распаковкой:

# Обработка словаря через цикл:
some_dict = {
	1: (1, 2, 3),
	2: (3, 4, 5),
	3: (5, 6, 7)
for value_1, value_2, value_3 in some_dict.values():
	print(value_1, value_2, value_3)
# Обработка значений кортежа:
some_tuple = ('A', 'B', 'C')
value_A, value_B, value_C = some_tuple
print(value_A, value_B, value_C)
# Вывод:
1 2 3
3 4 5
4 5 6
A B C

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

Пропуск итерации и прерывание цикла

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

Пропуск итерации обычно используется вместе с условием, чтобы не выполнять какое-то действие при определённом условии. Например:

for i in range(5):
    if i == 0 or i == 2 or i == 4:
        continue
	print(i)
# Вывод:
# 1
# 3

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

some_list = [1, 55, 342, 774]
valueToFind = 342
hasValue = False
for value in some_list:
    print('Checking value:', value)
    if value == valueToFind:
        hasValue = True
        break

if hasValue:
    print('Found value:', valueToFind)
else:
    print('Value', valueToFind, 'not found')
# Вывод:
# Checking value: 1
# Checking value: 55
# Checking value: 342
# Found value: 342

Функция range()

В Python есть встроенная функция, которая возвращает кортеж из N чисел – range(n). Её очень удобно использовать, если ты хочешь сделать что-то определённое количество раз. Пример:

for i in range(5):
	print(i)
# Вывод:
# 0
# 1
# 2
# 3
# 4

Задание на закрепление

Задание “стипендия”:

  • Есть словарь с данными студентов: ключ – ID студента, значение – словарь с (ФИО, оценками по всем предметам, посещаемостью)
  • Необходимо составить несколько списков студентов:
    • список на отчисление – средняя оценка меньше или равна 3.5 и посещаемость меньше или равна 0.7
    • список на стипендию – средняя оценка выше или равна 4 и посещаемость выше или равна 0.9
    • список на повышенную степендию – средняя оценка равна 5 и посещаемость 1
    • список студентов, которые не попали в другие списки
  • Выведи отдельно имена студентов из всех списков
  • Если студент находится в одном из списков, то его не должно быть в другом списке

Вот словарь с данными: файл

Цикл while

Вот пример определения цикла while:

value = 1
# Читается как: пока условие истинно делай
while value < 10:
	print(value, value*value)
	value += 1
# Квадрат числа 10 не выведется потому что условие "value < 10" уже не выполнится, когда value будет равен 10
# Вывод:
# 1 1
# 2 4
# 3 9
# 4 16
# 5 25
# 6 36
# 7 49
# 8 64
# 9 81

Цикл while используется реже чем for, но он тоже необходим для решения определённых задач. Вот пример:

import random
# На входе произвольное число от 1 до 100
value = random(1, 100)
# Нужно вывести все числа, которые делятся на 5 и 9
while value > 0:
	if value % 5 == 0 or value % 9 == 0:
		print(value)
	# Мы будем вычитать на каждом проходе цикла по единице, и так пройдём по всем оставшимся
	# значениям до момента, когда value будет равен 0 - тогда мы выйдем из цикла
	value -= 1

Оператор остаток от деления

Сейчас я использовал оператор, который ранее мы не встречали – это оператор “остаток от деления”. Он возвращает остаток после деления на заданное число – например:

12 % 5 # (12 / 5) - 2 целых, в остатке 2 -- оператор вернёт 2
4 % 6 # (4 / 6) - 0 целых, в остатке 4 -- оператор вернёт 4
25 % 5 # (25 / 5) - 5 целых, в остатке 0 -- оператор вернёт 0
for i in range(5):
    if i % 2 == 0:
        continue
# Вывод:
# 1
# 3

Задание на закрепление

Задание “взлом шифрования”:

  • Теория:
    • Один из самых популярных алгоритмов шифрования RSA работает за счёт произведения операций с простыми числами
    • Простые числа – числа, которые делятся только на себя и на 1 (и не является 1). Например: число 23 – простое, а число 27 – не простое (27 делится на 3 и 9)
    • В алгоритме шифрования RSA берётся 2 простых числа (приватный ключ) и перемножается, например: 13 * 23 == 299
    • Результат этого перемножения является публичным ключом, который используется для шифрования сообщений и является общедоступным
  • Твоя задача, зная публичный ключ 3403, найти из каких простых чисел он был создан (приватный ключ). Известно, что для его создания были использованы два простых числа, которые меньше 100
  • Сначала тебе надо будет составить список всех простых чисел до 100
    • попробуй сначала с помощью while пройти по всем числам от 1 до 100
    • потом придумай как ты можешь проверить что число в текущей итерации является простым (на картинке ниже я легко подтолкнул в нужном направлении)
  • Затем надо по очереди перемножить все простые числа друг с другом и сравнить с известным публичным ключом 3403, чтобы найти нужную комбинацию из двух чисел

Вот пояснение, которое может тебе помочь:

Поиск простых чисел

В этом примере было использовано два простых числа до 100, но в реальном мире для шифрования используются два числа, которые НАМНОГО больше 100. Вот, например, публичный ключ, которым шифрует свои данные google (можете попробовать подобрать два исходных простых числа, это займёт всего пару тысячелетий): 6200775413508788707869143248474167549822107185425627296325645173604849030956 7524007579084986705000752601808399633539399372401604287204692259087208312746262

Это одно число, я его просто разбил на два, а то не влезало в экран :)

Заключение

Итого, мы изучили:

  • Цикл for
  • Распаковка
  • Пропуск итерации и прерывание цикла
  • Функция range()
  • Цикл while
  • Простые числа

Если что – пиши, я помогу и постараюсь объяснить лучше.

Дальше мы рассмотрим функции – с помощью них ты сможешь разбить логику программы на отдельные блоки и меньше путаться при написании сложных программ.