Ранее, в главе про циклы, мы уже выяснили, что такое циклы и как они работают, поэтому в этой главе я не стану вновь останавливаться на этой теме.
В прошлых главах вы узнали, что такое циклы while и списки. Также, в главе про списки, вы научились перебирать элементы списков с помощтью цикла while. Однако, это не самый удобный способ, как вы могли заметить.
Но, как правило, когда речь идет о работе со списками и их переборе, программисты используют другие инструменты. В частности, цикл for.
Главное отличие for от while в том, что for автоматически проходит по всем элементам последовательности (например, по списку) и не требует ручного изменения счетчика, как это делается в цикле while. Также, как и в while, в нем используется условие, но только одного вида: это условие проверяет, есть ли некоторый элемент в последовательности.
Код цикла for на python
На самом деле цикл for в python, в отличие от большинства других ЯП, – крайне удобная вещь.
В других языках, таких как JavaScript, цикл for состоит из трех частей:
инициализация счетчика (например, i = 0)
условие (например, i < a.length, что ограничивает цикл по длине списка)
и изменение счетчика на каждой итерации (i++). В Python цикл for гораздо проще, так как он автоматически проходит по каждому элементу последовательности.
const a = [1, 2, 3, 4]
for (i = 0; i < a.length; i++){
console.log(a[i])
}
Как выглядит цикл в JS. Больше похож на while, не так ли?
Запись i++ эквивалентна записи i += 1
Также обратите внимание, что i здесь не сам элемент, а индекс элемента
Кстати! Переменная i тут не случайна. Программисты используют ее от слова increment (увеличение)
В python все работает иначе. Python использует специальный механизм, называемый протоколом итераторов, чтобы легко перебирать элементы списков и других структур данных.
Когда вы пишете цикл for, Python создает специальный объект — итератор, который проходит по каждому элементу списка. На каждом шаге он автоматически получает следующий элемент и присваивает его переменной, которую вы указываете.
Пример с итератором показывает, как работает цикл for “под капотом”. В реальной жизни вам вряд ли придется использовать итераторы напрямую, но понимание их механики может быть полезным.
a = [1, 2, 3]
i = iter(a) # Получаем итератор
print(next(i)) # 1
print(next(i)) # 2
print(next(i)) # 3
Ранее, в главе про циклы while, уже говорилось о том, как можно завершать циклы с помощью break, использовать else и continue. Повторяться не буду, для циклов for работает все то же самое. Соовтетственно else сработает после полного прохождения по элементам/range.
Создайте программу "for-exercise.py".
Создайте список, который содержит разные цвета (не меньше 5). Выведите все цвета на экран при помощи цикла for. Внутри print используйте атрибут end со значением "\n\t•"
print(1, end = "–")
Все, что перечислено внутри скобок функций, называется атрибутом
Продолжите работать в "for-exercise.py". Обозначьте комментарием, где начинается эта задача.
Пусть пользователь введет строку с числами через пробел и сохраните ее в переменную data_example. Преобразуйте строку в список чисел с помощью метода split(), и выведите элементы списка через длинное тире (–). Все числа, которые делятся на 3, замените на точку (•).
Продолжите работать в "for-exercise.py".
Обратите внимание, что у вас может быть немного "кривой" вывод. Как это можно исправить? Вспомните, что после циклов можно использовать, например, else, или обработайте последний вывод цвета через условие.
Обратите внимание: с помощью цикла for можно перебирать любые итерируемые объекты. Это не только списки, это и строки, и кортежи, и словари, и сеты и многое другое. Пока что речи об этих типах не было, но имейте это ввиду.
Когда мы хотим повторить одно и то же действие несколько раз, но при этом не перебираем конкретный список, на помощь приходит функция range. Она создает последовательность чисел, по которой можно “пробежаться” с помощью цикла for.
Функция range создает последовательность чисел по порядку. Например, range(5) создает последовательность из 5 чисел, о 0 до 4.
Но почему до 4, а не до 5? Потому что range(5) генерирует числа от 0 до 5, но не включая 5. Это важно помнить!
for i in range(5):
print(i)
По сути range создает список из чисел (0, 1, 2, 3, 4). Но нужно быть внимательным, range возвращает объект типа range, а не тип списка, как можно было бы подумать.
Мы можем не только указать, сколько всего чисел нужно, но и с какого числа начинать. Это особенно удобно, когда нужно начать "считать" с определенного числа.
for i in range(2, 6):
print(i)
В этом примере выведутся числа с 2 до 5 включительно
Иногда нам нужно пропускать числа. Для этого можно указать шаг — через какое количество чисел переходить.
for i in range(2, 11, 2):
print(i)
В этом примере выведутся числа 2, 4, 6, 8, 10
Помните, как в циклах while вы делали последовательность в обратном порядке? Здесь это можно тоже сделать. Для этого нужно задать отрицательный шаг. Естественно, начало должно быть больше, чем конец.
for i in range(10, -1, -1):
print(i)
В этом примере выведутся числа с 10 до 0 включительно.
Создайте файл "range-exerc.py".
Пусть пользователь напишет строку с неизвестным количеством чисел через пробел. Обработайте эту строку таким образом, чтобы ему вывелись:
Все числа в обратном порядке
Все числа, индекс которых четный
В программе используйте цикл for и range.
Ранее мы уже рассматривали вложенные циклы. Однако, возможно сейчас их структура вам станет более понятной.
Изучите код с картинки. Что он выведет? Почему так? Попробуйте переписать к себе этот код и запустить, чтобы проверить, правы вы или нет.
Этот код практически идентичен предыдущему. Однако, второй цикл смещен внутрь первого цикла (визуально он правее). Как вы помните, такие циклы называются вложенными.
Ответьте на следующие вопросы:
Сколько букв A и B выводится в первом и втором цикле?
Почему порядок вывода отличается?
Почему количество букв B во втором цикле - больше? Во сколько раз?
Что будет, если изменить во второй программе for j in range(3) на for j in range(5)? Сколько будет в таком случае букв B?
Генераторы списков — это короткий и удобный способ создания списков в Python. Вместо того чтобы использовать циклы for и добавлять элементы в список вручную, мы можем записать весь процесс создания списка в одну строку.
Генератор списка имеет следующий синтаксис:
[выражение for элемент in последовательность]
выражение — то, что мы хотим добавить в список.
for элемент in последовательность — цикл, который перебирает элементы последовательности (например, списка или диапазона).
Иногда нам нужно добавить в новый список только те элементы, которые соответствуют определенному условию. В этом случае мы можем добавить условие в генератор списка.
Компактность и читаемость
Генераторы списков позволяют создавать новые списки в одной строке, что делает код короче и более читаемым.
Производительность
Генераторы списков обычно работают быстрее, чем создание списка с помощью цикла for и метода append(), так как выполняются более оптимально внутри Python.
Гибкость
Можно использовать любые выражения и условия, чтобы контролировать, какие элементы добавляются в новый список.
Генераторы списков — это мощный инструмент в Python для создания списков с использованием краткой и эффективной записи. Они позволяют не только перебирать элементы последовательностей, но и использовать условия для фильтрации или создания сложных структур данных.
В целом, есть понятие генераторы, которое обозначет конкретный подход к созданию функций с использованием yield выражений. Об этом более подробно, а также о том, как хранятся данные с помощью таких генераторов, мы поговорим в разделе функций.
Создайте файл "generators.py".
В этом файле с помощью генераторов создайте два списка и выведите их на экран:
Список квадратов N чисел (пользователь должен ввести это число N)
Пользователь вводит список чисел через пробел. Сгенерируйте список, который фильтрует числа и оставляет только те, которые больше 0.
Enumerate в Python — это встроенная функция, которая позволяет одновременно перебирать элементы последовательности и отслеживать их индексы. Она особенно полезна в ситуациях, когда нужно знать как значение элемента, так и его позицию в последовательности.
Функция enumerate() применяется только для итерируемых объектов. Функция создает объект-генератор, который генерирует кортежи, состоящие из 2х элементов: индекса и самого элемента.
Однако, чаще используют деструктор прямо в заголовке цикла, чтобы няпрямую взаимодействовать с элементами кортежа.
Деструктор здесь - это i, elem, который принимает значения из кортежа по индексам.
– Что-то непонятно, что такое кортежи
– Кортежи, это по сути то же, что и списки. Но в отличие от списков - они не изменяются. В них нельзя добавить или удалить элементы, нельзя заменить. Зато они меньше места занимают и во многих случаях использовать кортежи интереснее. Поговорим про это подробнее в теме про map, set и прочие штуки.
Простота и удобство
Без enumerate для получения индексов вам пришлось бы вручную использовать счетчик или обращаться к элементам через индексы. Это выглядит громоздко.
Избегание ошибок
Когда вы вручную отслеживаете индексы, существует вероятность ошибиться в логике или забыть обновить счетчик. enumerate решает эту проблему, так как делает все автоматически.
Повышение читаемости
Если в коде используются и индексы, и элементы, использование enumerate делает код более читаемым, сразу показывая, что в нем участвуют как индексы, так и значения.
Чтобы точно разобраться с тем, в каких ситуациях это нужно, попробуйте выполнить несколько следующих упражнений.
Создайте файл "animals.py"
Пусть пользователь вводит список, например, планет солнечной системы. С помощью формат строки и enumerate выведите все элементы с порядковым номером, начиная с 1. Чтобы изменить начало индексации, используйте атрибут start в функции enumerate вторым аргументом.
Создайте файл "isindex.py"
Пусть пользователь вводит список чисел. Найдите и выведите все числа, чей индекс совпадает с числом. Используйте в этой программе for и enumerate.