Цикл "for" в Python — универсальная управляющая конструкция
Циклы являются мощнейшим инструментом, предоставляемым высокоуровневыми языками программирования. Эти управляющие конструкции позволяют многократно выполнять требуемую последовательность инструкций. Циклы в языке Python представлены двумя основными конструкциями: while
и for
.
Применение циклов
Концепция циклов — это не просто очередная абстрактная выдумка программистов. Повторяющиеся раз за разом операции окружают нас и в реальной жизни:
🥣 добавление щепотки приправ в варящийся бульон и помешивание его до тех пор, пока пакетик специй не закончится.
🕙 следование строгому расписанию каждый будний день, пока не наступят долгожданные выходные.
🌄 даже банальная смена времён года.
— всё это циклы, и представить нормальную жизнь без них попросту невозможно.
Впрочем, то же касается и программирования. Представьте, что вам нужно последовательно напечатать числа от 1 до 9999999999. В отсутствии циклов, эту задачу пришлось бы выполнять ручками, что потребовало бы колоссального количества кода и огромных временных затрат:
print(1)
print(2)
print(3)
# ...
# 9999999995 строк
# ...
print(9999999998)
print(9999999999)
Циклы же позволяют уместить такую многокилометровую запись в изящную и простую для понимания конструкцию, состоящую всего из двух строчек:
for i in range(1, 10000000000):
print(i)
Смысл её крайне прост. В основе цикла for
лежат последовательности, и в примере выше это последовательность чисел от 1 до 9999999999. for
поэлементно её перебирает и выполняет код, который записан в теле цикла. В частности, для решения данной задачи туда была помещена инструкция, позволяющая выводить значение элемента последовательности на экран.
Итерации
- Итерация (Iteration) — это одно из повторений цикла (один шаг или один "виток" циклического процесса). К примеру цикл из 3-х повторений можно представить как 3 итерации.
- Итерируемый объект (Iterable) — объект, который можно повторять. Проще говоря это объект, который умеет отдавать по одному результату за каждую итерацию.
- Итератор (iterator) — итерируемый объект, в рамках которого реализован метод __next__, позволяющий получать следующий элемент.
👉 Чтобы выполнить итерацию, Python делает следующее:
- Вызывает у итерируемого объекта метод
iter()
, тем самым получая итератор. - Вызывает метод
next()
, чтобы получить каждый элемент от итератора. - Когда метод next возвращает исключение
StopIteration
, цикл останавливается.
Пример создания итерируемого объекта Для того чтобы создать собственный класс итерируемого объекта, нужно всего лишь внутри него реализовать два метода: __iter__() и __next__():
- внутри метода __next__ () описывается процедура возврата следующего доступного элемента;
- метод __iter__() возвращает сам объект, что даёт возможность использовать его, например, в циклах с поэлементным перебором.
Создадим простой строковый итератор, который на каждой итерации, при получении следующего элемента (т.е. символа), приводит его к верхнему регистру:
class ToUpperCase:
def __init__(self, string_obj, position=0):
"""сохраняем строку, полученную из конструктора,
в поле string_obj и задаём начальный индекс"""
self.string_obj = string_obj
self.position = position
def __iter__(self):
""" возвращаем сам объект """
return self
def __next__(self):
""" метод возвращает следующий элемент,
но уже приведенный к верхнему регистру """
if self.position >= len(self.string_obj):
# исключение StopIteration() сообщает циклу for о завершении
raise StopIteration()
position = self.position
# инкрементируем индекс
self.position += 1
# возвращаем символ в uppercase-e
return self.string_obj[position].upper()
low_python = "python"
high_python = ToUpperCase(low_python)
for ch in high_python:
print(ch, end="")
> PYTHON
Синтаксис for
Как было замечено, цикл for
python — есть средство для перебора последовательностей. С его помощью можно совершать обход строк, списков, кортежей и описанных выше итерируемых объектов.
В простейшем случае он выглядит так:
for item in collection:
# do something
Если последовательность collection
состоит, скажем, из 10 элементов, for
будет поочерёдно обходить их, храня значение текущего элемента в переменной item
.
Принцип работы for
максимально схож с таковым у циклов foreach
, применяемых во многих других высокоуровневых языках.
aliceQuote = "The best way to explain it is to do it."
# с помощью цикла for посчитаем количество символов (с пробелами) в строке
# зададим счетчик
count = 0
# будем посимвольно обходить весь текст
for letter in aliceQuote:
# на каждой новой итерации:
# в переменной letter будет храниться следующий символ предложения;
# увеличиваем счетчик на 1;
count += 1
print(count)
> 39
range() и enumerate()
Вы уже наверняка запомнили, что for
работает с последовательностями. В программировании очень часто приходится повторять какую-то операцию фиксированное количество раз. А где упоминается "количество чего-то", существует и последовательность, числовая.
👉 Для того чтобы выполнить какую-либо инструкцию строго определенное число раз, воспользуемся функцией range()
:
# скажем Миру привет целых пять раз!
for i in range(5):
print("Hello World!")
>
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
range()
можно представлять, как функцию, что возвращает последовательность чисел, регулируемую количеством переданных в неё аргументов. Их может быть 1, 2 или 3:
range(stop)
;range(start, stop)
;range(start, stop, step)
.
Здесь start
— это первый элемент последовательности (включительно), stop
— последний (не включительно), а step
— разность между следующим и предыдущим членами последовательности.
# 0 - начальный элемент по умолчанию
for a in range(3):
print(a)
>
0
1
2
# два аргумента
for b in range(7, 10):
print(b)
>
7
8
9
# три аргумента
for c in range(0, 13, 3):
print(c)
>
0
3
6
9
12
👉 Чрезвычайно полезная функция enumerate()
определена на множестве итерируемых объектов и служит для создания кортежей на основании каждого из элементов объекта. Кортежи строятся по принципу (индекс элемента, элемент), что бывает крайне удобно, когда помимо самих элементов требуется ещё и их индекс.
# заменим каждый пятый символ предложения, начиная с 0-го, на *
text = "Это не те дроиды, которых вы ищете"
new_text = ""
for char in enumerate(text):
if char[0] % 5 == 0:
new_text += '*'
else:
new_text += char[1]
print(new_text)
> *то н* те *роид*, ко*орых*вы и*ете
break и continue
Два похожих оператора, которые можно встретить и в других языках программирования.
break
— прерывает цикл и выходит из него;continue
— прерывает текущую итерацию и переходит к следующей.
# break
for num in range(40, 51):
if num == 45:
break
print(num)
>
40
41
42
43
44
Здесь видно, как цикл, дойдя до числа 45 и вернув истину в условном выражении, прерывается и заканчивает свою работу.
# continue
for num in range(40, 51):
if num == 45:
continue
print(num)
>
40
41
42
43
44
46
47
48
49
50
В случае continue
происходит похожая ситуация, только прерывается лишь одна итерация, а сам же цикл продолжается.
else
Если два предыдущих оператора можно часто встречать за пределами Python, то else
, как составная часть цикла, куда более редкий зверь. Эта часть напрямую связана с оператором break
и выполняется лишь тогда, когда выход из цикла был произведен НЕ через break
.
group_of_students = [21, 18, 19, 21, 18]
for age in group_of_students:
if age < 18:
break
else:
print('Всё в порядке, они совершеннолетние')
> Всё в порядке, они совершеннолетние
Best practice
Цикл по списку
Перебрать list
в цикле не составляет никакого труда, поскольку список — объект итерируемый:
# есть список
entities_of_warp = ["Tzeench", "Slaanesh", "Khorne", "Nurgle"]
# просто берём список, «загружаем» его в цикл и без всякой задней мысли делаем обход
for entity in entities_of_warp:
print(entity)
>
Tzeench
Slaanesh
Khorne
Nurgle
Так как элементами списков могут быть другие итерируемые объекты, то стоит упомянуть и о вложенных циклах. Цикл внутри цикла вполне обыденное явление, и хоть количество уровней вложенности не имеет пределов, злоупотреблять этим не следует. Циклы свыше второго уровня вложенности крайне тяжело воспринимаются и читаются.
strange_phonebook = [
["Alex", "Andrew", "Aya", "Azazel"],
["Barry", "Bill", "Brave", "Byanka"],
["Casey", "Chad", "Claire", "Cuddy"],
["Dana", "Ditrich", "Dmitry", "Donovan"]
]
# это список списков, где каждый подсписок состоит из строк
# следовательно можно (зачем-то) применить тройной for
# для посимвольного чтения всех имён
# и вывода их в одну строку
for letter in strange_phonebook:
for name in letter:
for character in name:
print(character, end='')
> A l e x A n d r e w A y a A z a z e l B a r ...
Цикл по словарю
Чуть более сложный пример связан с итерированием словарей. Обычно, при переборе словаря, нужно получать и ключ и значение. Для этого существует метод .items()
, который создает представление в виде кортежа для каждого словарного элемента.
Цикл, в таком случае, будет выглядеть следующим образом:
# создадим словарь
top_10_largest_lakes = {
"Caspian Sea": "Saline",
"Superior": "Freshwater",
"Victoria": "Freshwater",
"Huron": "Freshwater",
}
# обойдём его в цикле for и посчитаем количество озер с солёной водой и количество озёр с пресной
salt = 0
fresh = 0
# пара "lake, water", в данном случае, есть распакованный кортеж, где lake - ключ словаря, а water - значение.
# цикл, соответственно, обходит не сам словарь, а его представление в виде пар кортежей
for lake, water in top_10_largest_lakes.items():
if water == 'Freshwater':
fresh += 1
else:
salt += 1
print("Amount of saline lakes in top10: ", salt)
print("Amount of freshwater lakes in top10: ", fresh)
> Amount of saline lakes in top10: 1
> Amount of freshwater lakes in top10: 3
Цикл по строке
Строки, по сути своей — весьма простые последовательности, состоящие из символов. Поэтому обходить их в цикле тоже совсем несложно.
word = 'Alabama'
for w in word:
print(w, end=" ")
> A l a b a m a
Цикл for с шагом
Цикл for
с шагом создается при помощи уже известной нам функции range
, куда, в качестве третьего по счету аргумента, нужно передать размер шага:
# выведем числа от 100 до 1000 с шагом 150
for nums in range(100, 1000, 150):
print(nums)
>
100
250
400
550
700
850
Цикл for со счетчиком итераций
Счетчик итераций может понадобиться, если обходить циклом for
списки с данными. Например, если нужно логировать номер каждой итерации или остановить цикл for
по достижении лимита.
В цикле for
нет встроенного счетчика итераций, но его можно сделать несколькими способами:
Способ #1 — через функцию enumerate(), она генерирует кортеж вида (индекс элемента, элемент):
step_names = ["up", "down", "up", "up", "down"]
for i, step_name in enumerate(step_names):
print(f"step #{i + 1} — {step_name}")
> step #1 — up
> step #2 — down
> step #3 — up
> step #4 — up
> step #5 — down
Способ #2 — через функцию zip(), она группирует данные в кортежи и останавливается, когда заканчиваются элементы:
step_names = ["up", "down", "up", "up", "down"]
step_names_len = len(step_names)
for i, step_name in zip(range(step_names_len), step_names): # лимит = 5
print(f"step #{i + 1} — {step_name}")
> step #1 — up
> step #2 — down
> step #3 — up
> step #4 — up
> step #5 — down
Обратный цикл for
Если вы еще не убедились в том, что range()
полезна, то вот ещё пример: благодаря этой функции можно взять и обойти последовательность в обратном направлении.
# выведем числа от 40 до 50 по убыванию
# для этого установим step -1
for nums in range(50, 39, -1):
print(nums)
>
50
49
48
47
46
45
44
43
42
41
40
for в одну строку
Крутая питоновская фишка, основанная на так называемых list comprehensions
или, по-русски, генераторов. Их запись, быть может, несколько сложнее для понимания, зато очевидно короче и, по некоторым данным, она работает заметно быстрее на больших массивах данных.
В общем виде генератор выглядит так:
[результирующее выражение | цикл | опциональное условие]
Приведем пример, в котором продублируем каждый символ строки inputString
:
# здесь letter * 2 — результирующее выражение; for letter in inputString — цикл, а необязательное условие опущено
double_letter = [letter * 2 for letter in "Banana"]
print(double_letter)
> ['BB', 'aa', 'nn', 'aa', 'nn', 'aa']
Другой пример, но теперь уже с условием:
# создадим список, что будет состоять из четных чисел от нуля до тридцати
# здесь if x % 2 == 0 — необязательное условие
even_nums = [x for x in range(30) if x % 2 == 0]
print(even_nums)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
Автор данной статьи настоящий гигачад, спасибо)
Здравствуйте, как сделать чтобы цикл
for
автоматически присваивал номерацию? Пример: 1 up 2 up 3 upДобрый день! Добавил информацию в раздел "Best practice → Цикл for со счетчиком итераций".
for i in data
и чтобы здесь можно было ввести ограничение сколько раз. Так можно?В цикле
for
нет возможности задать лимит повторений. Но вашу задачу можно решить как минимум 3-мя способами.Способ #1 — функция enumerate() генерирует кортежи вида (индекс элемента, элемент):
for i, element in enumerate(data): if i >= 3: # лимит = 3 break # ниже основной код
Способ #2 — функция zip() группирует данные в кортежи и останавливается, когда заканчиваются элементы:
for _, item in zip(range(3), data): # лимит = 3 print(item)
Способ #3 — использовать срезы (для списков, кортежей, строк):
for item in data[:3]: # лимит = 3 print(item)
А как сделать цикл
for
с шагом 0.1??Если вы генерируете список чисел через
range
, то указать шаг 0.1 не получится. Информация есть в статье проrange
, в разделе "range и тип float".Если вы хотите использовать числа с шагом 0.1 для дальнейших операций с числами, можно сделать так:
for i in range(0, 11, 1): print(i / 10.0) > 0.0 > 0.1 > 0.2 > 0.3 > 0.4 > 0.5 > ..
Альтернаятивный вариант — заранее сгенерировать список чисел с шагом 0.1:
float_numbers = (x / 10.0 for x in range(0, 11, 1)) for i in float_numbers: print(i) > 0.0 > 0.1 > 0.2 > 0.3 > 0.4 > 0.5 > ..
Подскажи пожалуйста, как мне заставить питон посчитать сколько чисел он сам вывел в терминал.
N = int(input("Введите натуральное число: ")) for N in range(N): # Цикл в последовательности 1-99 if(N % 2 != 0 and N % 3 != 0 and N % 5 != 0): print(N)
Вот такого вида код, то есть в терминале выдастся последовательность, к примеру: 12 13 14 Нужно чтобы в конце было "Всего чисел 3"
Добрый день! Можно сделать через счётчик:
N = int(input("Введите натуральное число: ")) sum = 0 for N in range(N): # Цикл в последовательности 1-99 if (N % 2 != 0 and N % 3 != 0 and N % 5 != 0): sum += 1 print(N) print(f"Всего чисел {sum}")
Даже для такого новичка как я и то понятно огромное спасибо!
Не всё было понятно сразу, а так круто.
Если что-то непонятно, можете спрашивать в комментариях 😉
Коротко и ясно.
Доброй ночи Pythonchik! Подскажи пожалуйста как мне в этом коде дописать, чтобы он выводил в терминал 2-9+4=-3 и тому подобное? Буду очень признателен за помощь
q = 0 # переменная, увеличивающася на 1 каждую итерацию, нужна чтобы чередовать + и - n = input() # число, с цифрами которого работаем s = 0 # переменная в коорую посчитаем результат for i in n: # перебиаем цифры числа n q = q + 1 # увеличиваем q на 1 if q % 2 == 1: # если q нечётное s += int(i) # тогда будем прибавлять else: # если q чётное s -= int(i) # тогда будем вычитать print("Знакочередующаяся сумма цифр числа", n, "составляет:", s) # выводим итог на экран print("Программа завершила выполнение")
Если вам нужно отображать все операции над цифрами, можно сделать так:
q = 0 # переменная, увеличивающася на 1 каждую итерацию, нужна чтобы чередовать + и - n = input() # число, с цифрами которого работаем s = 0 # переменная в коорую посчитаем результат ops = [] # переменная в коорую пишутся все операции сложения/вычитания for i in n: # перебиаем цифры числа n q = q + 1 # увеличиваем q на 1 if q % 2 == 1: # если q нечётное s += int(i) # тогда будем прибавлять ops.append(f"+{i}") else: # если q чётное s -= int(i) # тогда будем вычитать ops.append(f"-{i}") print(f"Знакочередующаяся сумма цифр числа {n} составляет {''.join(ops)}={s}") # выводим итог на экран print("Программа завершила выполнение")
Из личных рекомендаций по коду, советую ознакомиться с этими статьями:
months = ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'] for entity in months: print(months)
Выдаёт текст в скобках на протяжении 12 строк, что делать?
Вместо
print(months)
нужноprint(entity)
.