Содержание:развернуть
- Применение циклов
- Итерации
- Синтаксис for
- range() и enumerate()
- break и continue
- else
- Best practice
-
Цикл по списку
-
Цикл по словарю
-
Цикл по строке
-
Как сделать цикл for с шагом
-
Обратный цикл for
-
for в одну строку
Циклы являются мощнейшим инструментом, предоставляемым высокоуровневыми языками программирования. Эти управляющие конструкции позволяют многократно выполнять требуемую последовательность инструкций. Циклы в языке Python представлены двумя основными конструкциями: while
и for
.
Подробнее о циклах while вы можете прочитать здесь:
Применение циклов
Концепция циклов — это не просто очередная абстрактная выдумка программистов. Повторяющиеся раз за разом операции окружают нас и в реальной жизни:
🥣 добавление щепотки приправ в варящийся бульон и помешивание его до тех пор, пока пакетик специй не закончится.
🕙 следование строгому расписанию каждый будний день, пока не наступят долгожданные выходные.
🌄 даже банальная смена времён года.
— всё это циклы, и представить нормальную жизнь без них попросту невозможно.
Впрочем, то же касается и программирования. Представьте, что вам нужно последовательно напечатать числа от 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
Подробнее о функции range тут:
👉 Чрезвычайно полезная функция 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
Если вы еще не убедились в том, что 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 в Python.
Мы начнем с пары основных примеров и их синтаксиса. Далее обсудим, когда может быть полезен блок else, связанный с циклом for. Затем мы разберем итерактивные объекты (iterable), итераторы (iterator) и протокол итератора. Также узнаем, как создавать собственные итераторы и итерируемые объекты. После этого мы обсудим, как цикл for реализован с использованием итерактивных объектов и итераторов. Потом мы рассмотрим реализацию логики цикла for, используя цикл while и используя протокол итератора.
И наконец, для тех, кому интересно, мы разберем простой цикл for и пройдемся по инструкциям, которые интерпретатор Python выполняет при выполнении цикла for. Это должно помочь понять, что именно происходит внутри, во время работы цикла for.
Оператор for является одним из двух операторов, используемых для создания циклов в Python, другим является оператор while. Если вы совсем не знакомы с итерациями в Python, то рекомендуем почитать статью Итерации в Python: операторы for, while, break и continue которая будет хорошей отправной точкой для изучения циклов и итераций.
Простой цикл for
Давайте начнем с простого цикла for, который перебирает список строк и печатает каждую строку.
>>> for word in ["You", "are", "awesome!"]: ... print(word) ... You are awesome!
Как видите, цикл перебирает все слова в списке и печатает их. То есть на каждом шаге цикла переменной word присваивается элемент списка, а затем выполняется кодовый блок. Поскольку список – это упорядоченная последовательность элементов, цикл проходит по ним в том же порядке.
Цикл for с условием else
В Python цикл for может иметь необязательное условие else. Кодовый блок в предложении else выполняется после завершения цикла for, то есть после того, как все элементы итерируемого элемента были исчерпаны. Теперь давайте посмотрим, как мы можем расширить предыдущий пример, чтобы включить условие else.
>>> for word in ["You", "are", "awesome!"]: ... print(word) ... else: ... print("See you later!") ... You are awesome! See you later!
Когда полезно условие else?
Как вы могли заметить, блок else выполняется после завершения цикла for. Так какой смысл использовать блок else? Разве не будет выполнен следующий набор операторов после цикла for?
Ну, во многих случаях у нас возникают ситуации, когда нам нужно выйти из цикла for, когда выполняется определенное условие. И если это условие никогда не выполняется, но нам все равно нужно выполнить набор операторов. Для этого мы обычно используем логический флаг. Давайте посмотрим на пример.
def search(search_list, search_item): found_item = False for word in search_list: if word == search_item: found_item = True print("Found word '{}'".format(search_item)) break if not found_item: print("Word '{}' was not found!".format(search_item))
Использование:
>>> search(["You", "are", "awesome!"], "are") Found word 'are' >>> search(["You", "are", "awesome!"], "we") Word 'we' was not found!
С помощью блока else мы можем избежать использования логического флага found_item. Давайте посмотрим, как мы можем переписать вышеуказанный метод с помощью else. Обратите внимание, что блок else будет пропущен, если в цикле for встречается оператор break.
def search(search_list, search_item): for word in search_list: if word == search_item: print("Found word '{}'".format(search_item)) break else: print("Word '{}' was not found!".format(search_item))
Таким образом, блок else действительно полезен, только если у нас есть оператор break в цикле for, и нам нужно, чтобы выполнился набор операторов, если условие break никогда не выполнялось.
В противном случае операторы, связанные с else, просто выполняются в конце цикла for. Вы увидите это, когда мы разберем байт-код в последнем разделе этой статьи.
Синтаксис цикла for
Теперь, когда мы рассмотрели несколько основных примеров, давайте завершим этот раздел синтаксисом цикла for.
for <element> in <iterable>: <set_of_statements_1> else: <set_of_statements_2>
По сути, для каждого итерируемого элемента выполняется set_of_statements_1. Как только все элементы исчерпаны, управление переходит к блоку else и выполняется set_of_statements_2.
Обратите внимание, что предложение else является необязательным. Если блок else отсутствует, цикл завершается после того, как все элементы будут пройдены, и управление переходит к следующему оператору программы.
Итерируемые объекты (iterables) и итераторы (iterators)
Итерируемые объекты
В предыдущем разделе мы использовали термин «iterables» для обозначения объекта, который итерировался циклом for. Теперь давайте попробуем понять, что такое итерируемый объект в Python.
В Python итерируемый объект – это любой объект, который можно использовать в итерации с использованием цикла for. Это означает, что объект должен возвращать итератор при передаче в метод iter(). Давайте посмотрим примеры некоторых часто используемых встроенных итерируемых объектов в Python.
>>> iter("You are awesome!") # String <str_iterator object at 0x1041ad2e8> >>> iter(["You", "are", "awesome!"]) # List <list_iterator object at 0x1041ad358> >>> iter(("You", "are", "awesome!")) # Tuple <tuple_iterator object at 0x1041ad390> >>> iter({"You", "are", "awesome!"}) # Set <set_iterator object at 0x1041ac678> >>> iter({1: "You", 2: "are", 3: "awesome!"}) # Dictionary <dict_keyiterator object at 0x10400df48> >>> iter(range(3)) # Range function <range_iterator object at 0x1041a1450>
Как вы можете видеть, когда мы вызываем iter() для итерируемого объекта, он возвращает объект итератора.
Итераторы
А что такое итератор? В Python итератор определяется как объект, представляющий поток данных. По сути, если мы передаем итератор во встроенный метод next(), он должен вернуть следующее значение из связанного потока данных. Когда все элементы исчерпаны, должно появиться исключение StopIteration. Он должен продолжать вызывать исключение StopIteration для любых последующих вызовов метода next().
Примеры итератора со списком.
>>> my_list = ["You", "are", "awesome!"] >>> >>> # Get the iterator. ... list_iterator = iter(my_list) >>> >>> # Get next element of iterator. ... next(list_iterator) 'You' >>> next(list_iterator) 'are' >>> next(list_iterator) 'awesome!' >>> next(list_iterator) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> next(list_iterator) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
Итераторы тоже итеративные объекты! Но..
Следует помнить одну интересную вещь: итераторы сами по себе также поддерживают (обязаны поддерживать согласно протоколу итератора) метод iter(). Это означает, что мы можем вызвать метод iter() для итератора и получить сам объект итератора.
>>> my_list = ["You", "are", "awesome!"] >>> list_iterator = iter(my_list) >>> list_iterator <list_iterator object at 0x1099a6320> >>> iterator_of_iterator = iter(list_iterator) >>> iterator_of_iterator <list_iterator object at 0x1099a6320>
Таким образом, мы можем использовать итераторы везде, где ожидается итерация, например, в цикле for.
Однако обратите внимание, что вызов iter() для объекта-контейнера, такого как list, каждый раз будет возвращать новый итератор. Но вызов iter() для итератора просто возвращает тот же объект.
>>> my_list = [1, 2] >>> iter(my_list) <list_iterator object at 0x1099a62b0> >>> iter(my_list) # This gives a fresh iterator object <list_iterator object at 0x1099a62e8>
>>> my_list = [1, 2] >>> list_iter = iter(my_list) >>> list_iter <list_iterator object at 0x1099a62b0> >>> iter(list_iter) # This returns the same iterator object <list_iterator object at 0x1099a62b0> >>> iter(list_iter) # This returns the same iterator object <list_iterator object at 0x1099a62b0>
Итерация по списку дважды
Обратите внимание, что это работает так, как мы ожидали.
>>> my_list = ["You are Awesome!"] >>> >>> for word in my_list: ... print(word) ... You are Awesome! >>> for word in my_list: ... print(word) ... You are Awesome!
Итерация через list_iterator дважды
Обратите внимание, что итератор будет исчерпан в первом цикле, а во второй раз мы просто видим пустой контейнер.
>>> my_list = ["You are Awesome!"] >>> list_iterator = iter(my_list) >>> >>> for word in list_iterator: ... print(word) ... You are Awesome! >>> >>> for word in list_iterator: ... print(word) ... >>>
Протокол итератора
В предыдущем разделе мы увидели, что:
- Итерируемый объект при передаче в функцию iter() возвращает итератор.
- Итератор,
- при передаче в функцию next() возвращает следующий элемент или вызывает StopIteration после того, как все элементы будут исчерпаны.
- при передаче функции iter() возвращает себя.
Протокол итератора – это не что иное, как стандартный способ определения объектов как итераторов. Мы уже видели протокол в действии в предыдущем разделе. Согласно протоколу, итераторы должны определить следующие два метода:
- __next()__
- Этот метод должен возвращать следующий элемент серии каждый раз, когда он вызывается. Как только все элементы исчерпаны, должно появиться исключение StopIteration.
- Этот метод вызывается изнутри, когда мы вызываем встроенный метод next().
- __iter()__
- Этот метод должен возвращать сам объект итератора.
- Это метод, который вызывается внутри, когда мы вызываем встроенный метод iter().
Создание своего собственного итератора
Теперь, когда мы рассмотрели, как работает протокол итераторов, мы можем создавать свой собственный итератор. Давайте посмотрим на простой пример, где мы создаем наш собственный класс Range, который генерирует числа в данном диапазоне с заданным шагом.
class Range: def __init__(self, start, stop, step): self.next = start self.stop = stop self.step = step def __next__(self): if self.next > self.stop: raise StopIteration next_item = self.next self.next += self.step return next_item def __iter__(self): return self
Теперь посмотрим, как он работает с циклом for.
>>> for num in Range(1, 10, 2): ... print(num) ... 1 3 5 7 9
Обратите внимание, что экземпляр Range является как итерируемым объектом, так и итератором.
Создание своего собственного итерируемого объекта
Все, что для этого нужно, это возвращать новый итератор всякий раз, когда вызывается метод __iter__() , т. е. в этом случае он должен возвращать новый экземпляр Range.
class RangeIterable: def __init__(self, start, stop, step): self.start = start self.stop = stop self.step = step def __iter__(self): return Range(self.start, self.stop, self.step)
Давайте теперь используем наш RangeIterable с циклом for.
>>> for num in RangeIterable(1, 10, 2): ... print(num) ... 1 3 5 7 9
Как работает цикл for?
Теперь, когда мы поняли, что такое итератор и итерируемый объект, мы можем глубже понять, как на самом деле работает цикл for.
Давайте снова посмотрим на наш предыдущий пример.
>>> for word in ["You", "are", "awesome!"]: ... print(word) ... else: ... print("See you later!") ... You are awesome! See you later!
Когда мы выполняем вышеуказанный блок кода, происходит следующее:
- Оператор for внутри себя вызывает iter() для списка [«You», «are», «awesome!»]. Это приводит к получению итератора.
- Затем вызывается next() для итератора, и возвращаемое им значение присваивается переменной цикла, в данном случае word.
- После этого выполняется блок оператора, связанный с циклом for. В этом случае print(word).
- Шаги 2 и 3 повторяются до тех пор, пока next() не вызовет StopIteration.
- Как только next() вызывает StopIteration, управление переходит к предложению else, если оно присутствует, и выполняется блок операторов, связанных с else.
Примечание. Если в блоке кода, связанном с циклом for, встречается оператор break, то блок else пропускается.
Реализация логики цикла for с помощью оператора while
Мы могли бы реализовать вышеуказанную логику, используя оператор while следующим образом.
my_list = ["You", "are", "awesome!"] list_iter = iter(my_list) while True: try: word = next(list_iter) print(word) except StopIteration: print("See you later!") break
Цикл while ведет себя точно так же, как наш цикл for, и выдает следующий результат.
You are awesome! See you later!
Разбор цикла for
В этом разделе мы разберем цикл for и пройдемся по инструкциям, которые интерпретатор исполняет при выполнении цикла for. Мы будем использовать модуль dis для разборки цикла for. Чтобы быть точным, мы будем использовать метод dis.dis, чтобы получить удобочитаемое представление дизассемблированного байт-кода.
Мы будем использовать тот же простой цикл for, который мы рассматривали до сих пор. Запишем следующий цикл for в файл for_loop.py.
for word in ["You", "are", "awesome!"]: print(word) else: print("See you later!")
Теперь мы можем получить читаемую форму байт-кода, вызвав dis.dismethod. Запустим следующую команду в терминале.
$ python3 -m dis for_loop.py 1 0 SETUP_LOOP 28 (to 30) 2 LOAD_CONST 0 (('You', 'are', 'awesome!')) 4 GET_ITER >> 6 FOR_ITER 12 (to 20) 8 STORE_NAME 0 (word) 2 10 LOAD_NAME 1 (print) 12 LOAD_NAME 0 (word) 14 CALL_FUNCTION 1 16 POP_TOP 18 JUMP_ABSOLUTE 6 >> 20 POP_BLOCK 4 22 LOAD_NAME 1 (print) 24 LOAD_CONST 1 ('See you later!') 26 CALL_FUNCTION 1 28 POP_TOP >> 30 LOAD_CONST 2 (None) 32 RETURN_VALUE
Каждый из столбцов в разобранном виде представляет следующее:
- Колонка 1: номер строки кода.
- Колонка 2: знак «>>», если инструкция является целью перехода.
- Колонка 3: смещение байт кода в байтах.
- Колонка 4: инструкция байт-кода.
- Колонка 5: аргументы инструкции. В скобках отображается более понятный для человека имя аргументов.
Теперь давайте шаг за шагом пройдемся по нашему разобранному байт-коду и попытаемся понять, что на самом деле происходит.
В этом описание термин TOS означает вершина стека (top of the stack)
- строка 1, “for word in [“You”, “are”, “awesome!”]:” переводится как:
- 0 SETUP_LOOP 28 (to 30)
- Этот оператор помещает блок для цикла for в стек. Блок занимает от этой инструкции до 28 байт, то есть до «30»
- Это означает, что если в цикле for есть оператор break, управление переместится на «30» байт. Обратите внимание, блок else, будет пропущен если встретится оператор break.
- 2 LOAD_CONST 0 ((‘You’, ‘are’, ‘awesome!’))
- Затем список помещается на вершину стека (TOS).
- 4 GET_ITER
- Эта инструкция выполняет «TOS = iter (TOS)». Это означает, что итератор получается из списка, который на данный момент является TOS, а затем итератор переносится в TOS.
- 6 FOR_ITER 12 (to 20)
- Эта инструкция получает TOS, который на данный момент является нашим итератором, и вызывает для него метод next().
- Если next() возвращает значение, оно помещается в стек, и будет выполнена следующая инструкция «8 STORE_NAME».
- Как только функция next() указывает, что итератор исчерпан (т. к. сработал StopItered), TOS (а именно итератор) будет извлечен из стека, а счетчик байтового кода будет увеличен на 12. Это означает, что элемент управления перейдет к инструкция «20 POP_BLOCK».
- 8 STORE_NAME 0 (word)
- Эта инструкция преобразуется в word = TOS, то есть значение, возвращаемое функцией next(), будет присвоено переменной word.
- 0 SETUP_LOOP 28 (to 30)
- строка 2, “print(word)” переводится как:
- 10 LOAD_NAME 1 (print)
- Эта команда помещает команду print в стек.
- 12 LOAD_NAME 0 (word)
- Это команда перемещает аргумент print, то есть word в стек.
- 14 CALL_FUNCTION 1
- Это команда вызывает функцию с позиционными аргументами.
- Аргументы, связанные с функцией, будут присутствовать в TOS, как мы видели в предыдущей инструкции. Все аргументы выталкиваются до тех пор, пока не получит вызываемый объект, то есть print.
- Как только он получает вызываемый объект, он вызывается путем передачи ему всех аргументов.
- Как только вызов выполнен, его возвращаемое значение будет передано в TOS. В текущий момент это будет None.
- 16 POP_TOP
- TOS, то есть возвращаемое значение из функции удаляется (выталкивается) из стека.
- 18 JUMP_ABSOLUTE 6
- Счетчик байт-кода теперь установлен на «6». Это означает, что следующая выполняемая инструкция будет «6 FOR_ITER». Вот так цикл проходит по элементам итератора.
- Обратите внимание, что инструкция «6 FOR_ITER» заставит программу выйти из этого цикла и перейти к «20 POP_BLOCK», как только все элементы итератора будут исчерпаны.
- 20 POP_BLOCK
- POP_BLOCK приведет к удалению блока, установленного в «0 SETUP_LOOP», из стека блоков.
- 10 LOAD_NAME 1 (print)
- Обратите внимание, что номер строки 3, т.е., else, не имеет каких-либо конкретных инструкций, связанных с этим. Управление программой естественным образом переходит к следующей инструкции, которая в основном состоит из операторов, связанных с else.
- строка 4, “print(“See you later!”)” переводится как:
- 22 LOAD_NAME 1 (print)
- Вызываемый объект, связанный с print, помещается в стек.
- 24 LOAD_CONST 1 (‘See you later!’)
- Аргументы для вызываемого объекта помещаются в стек.
- 26 CALL_FUNCTION 1
- Аргументы для print и команда print извлекаются из стека. Затем выполняется вызываемая функция, и ее возвращаемое значение передается в TOS.
- 28 POP_TOP
- TOS, то есть возвращаемое значение функции (в данном случае None) удаляется из стека.
- 22 LOAD_NAME 1 (print)
- Следующие две инструкции в основном загружают возвращаемое значение нашего скрипта (None) в стек и возвращают его.
- 30 LOAD_CONST 2 (None)
- 32 RETURN_VALUE
Вув! Итак, мы закончили с разборкой инструкций для цикла for. Я надеюсь, что это поможет немного лучше понять работу цикла for.
Заключение
В этом посте мы рассмотрели следующее:
- Как написать цикл for в Python?
- Как использовать else, связанное с циклом for?
- Что такое итераторы и итерируемые объекты?
- Что такое протокол итератора?
- Как создать итератор и итерируемый объект?
- Как работает цикл for?
- Как используя цикл while имитировать цикл for?
- Как разобрать цикл for с помощью модуля dis и увидеть понятные человеку инструкции, выполняемые интерпретатором Python? Как читать и понимать разобранные инструкции?
Оригинальная статья Shyama Sankar Understanding for-loops in Python
Была ли вам полезна эта статья?
Цикл for в Python – это итеративная функция. Если у вас есть объект последовательности, например список, вы можете использовать цикл for для перебора элементов, содержащихся в списке.
Функциональность цикла for не сильно отличается от того, что вы видите во многих других языках программирования.
Содержание
- Базовый синтаксис
- Как вывести отдельные буквы строки?
- Использование цикла for для перебора списка или кортежа
- Вложенный цикл
- Использование с функцией range()
- Оператор break
- Оператор continue
- С (необязательным) блоком else
Базовый синтаксис
Мы можем использовать цикл for для перебора списка, кортежа или строк. Синтаксис:
for itarator_variable in sequence_name: Statements . . . Statements
Как вывести отдельные буквы строки?
Строка Python – это последовательность символов. Мы можем использовать цикл for для перебора символов и их печати.
word="anaconda" for letter in word: print (letter)
Вывод:
a n a c o n d a
Список и кортеж – повторяемые объекты. Мы можем использовать цикл для перебора их элементов.
words= ["Apple", "Banana", "Car", "Dolphin" ] for word in words: print (word)
Вывод:
Apple Banana Car Dolphin
Давайте посмотрим на пример, чтобы найти сумму чисел в кортеже:
nums = (1, 2, 3, 4) sum_nums = 0 for num in nums: sum_nums = sum_nums + num print(f'Sum of numbers is {sum_nums}') # Output # Sum of numbers is 10
Вложенный цикл
Когда у нас есть цикл for внутри другого цикла for, он называется вложенным циклом for. В следующем коде показаны вложенные циклы:
words= ["Apple", "Banana", "Car", "Dolphin" ] for word in words: #This loop is fetching word from the list print ("The following lines will print each letters of "+word) for letter in word: #This loop is fetching letter for the word print (letter) print("") #This print is used to print a blank line
Вывод
Использование с функцией range()
Python range() – одна из встроенных функций. Она используется с циклом for для выполнения блока кода определенное количество раз.
for x in range(3): print("Printing:", x) # Output # Printing: 0 # Printing: 1 # Printing: 2
Мы также можем указать параметры запуска, остановки и шага для функции диапазона.
for n in range(1, 10, 3): print("Printing with step:", n) # Output # Printing with step: 1 # Printing with step: 4 # Printing with step: 7
Оператор break
Оператор break используется для преждевременного выхода из цикла for. Он используется для прерывания цикла при выполнении определенного условия.
Допустим, у нас есть список чисел, и мы хотим проверить, присутствует ли число. Мы можем перебрать список чисел и, если число найдено, выйти из цикла, потому что нам не нужно продолжать перебирать оставшиеся элементы.
В этом случае мы будем использовать условие if else.
nums = [1, 2, 3, 4, 5, 6] n = 2 found = False for num in nums: if n == num: found = True break print(f'List contains {n}: {found}') # Output # List contains 2: True
Оператор continue
Мы можем использовать операторы continue внутри цикла, чтобы пропустить выполнение тела цикла for для определенного условия.
Допустим, у нас есть список чисел, и мы хотим вывести сумму положительных чисел. Мы можем использовать операторы continue, чтобы пропустить цикл для отрицательных чисел.
nums = [1, 2, -3, 4, -5, 6] sum_positives = 0 for num in nums: if num < 0: continue sum_positives += num print(f'Sum of Positive Numbers: {sum_positives}')
С (необязательным) блоком else
Блок else выполняется только в том случае, если цикл не завершается оператором break.
Допустим, у нас есть функция для вывода суммы чисел, когда все числа четные. Мы можем использовать оператор break, чтобы завершить цикл for, если присутствует нечетное число. Мы можем вывести сумму в части else, чтобы она выводилась, когда цикл выполняется нормально.
def print_sum_even_nums(even_nums): total = 0 for x in even_nums: if x % 2 != 0: break total += x else: print("For loop executed normally") print(f'Sum of numbers {total}') # this will print the sum print_sum_even_nums([2, 4, 6, 8]) # this won't print the sum because of an odd number in the sequence print_sum_even_nums([2, 4, 5, 8]) # Output # For loop executed normally # Sum of numbers 20
( 3 оценки, среднее 5 из 5 )
Как и большинство программистов, вы знаете, что после создания массива, вам нужно написать цикл для его обработки. С этим нет никаких проблем, но иногда нам не нужно использовать несколько строк для написания полного цикла for для одной простой задачи. К частью, Python это понимает и предоставляет замечательный инструмент для использования в таких ситуациях. Этот инструмент называется генератор списка (list comprehensions, списковое включение).
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Telegram Чат & Канал
Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Что это за зверь?
Списковое включение (List comprehensions) – это списки, которые генерируются с циклом for внутри. Они очень распространены в Python и выглядят примерно следующим образом:
[thing for thing in list_of_things] |
Возможно, вы еще сильнее запутались, так что сделаем шаг назад. Список содержит в себе множество вещей, но определяется между квадратными скобками. Скажем, мне нужно получить функцию, которая удваивает значения всех чисел в списке. Для начала, мне нужно создать список чисел.
Теперь создадим функцию. Назовем ее list_doubler
, так как это именно то, что она делает, и она будет принимать аргумент, который является списком, который мы будем удваивать.
def list_doubler(lst): doubled = [] for num in lst: doubled.append(num*2) return doubled |
Вызов этой функции даст нам новый список с удвоенными элементами.
my_doubled_list = list_doubler(lst) |
my_doubled_list
теперь содержит значения 42
, 4
и 186
. Эта функция простая и делает то, что нам нужно простым способом, но это пять строк, учитывая определяющую строку. Также есть переменная, с которой мы ничего не делаем, кроме как добавляем и в конце возвращаем её.
Единственная часть функции, которая по-настоящему работает – это цикл for. Цикл for тоже мало что делает, просто умножает число на 2. Это идеальный кандидат для превращения в списковое включение.
Создание спискового включения
Давайте сохраним его как функцию, которую мы будем вызывать. Нам нужно только упростить тело функции. Так как списковое включение создает списки, а списки могут быть назначены к переменным, примем это во внимание и расположим списковое включение справа от doubled
и продолжим.
doubled = [thing for thing in list_of_things] |
Хорошо, теперь нам нужно заполнить правую сторону. Как и с нормальным циклом for, а правая часть списка выглядит именно так, нам нужно назвать элементы в нашем цикле. Сначала, назовем каждый объект, и мы также будем использовать переменную списка, которая будет передана.
doubled = [thing for num in lst] |
Это не может работать в полной мере, так как элемент не является… элементом. В нашей изначальной функции мы выполнили num * 2
, так что давайте сделаем это еще раз.
doubled = [num * 2 for num in lst] |
Все что находится перед циклом for
точно внесено в список. Наконец, нам нужно вернуть наш новый список.
def list_doubler(lst): doubled = [num * 2 for num in lst] return doubled |
Запускаем нашу новую функцию.
my_doubled_list = list_doubler([12, 4, 202]) |
И да, my_doubled_list
содержит ожидаемые значения 24
, 8
и 404
. Отлично, все работает! Но так как мы создаем и моментально возвращаем переменную, давайте просто применим списковое включение напрямую.
def list_doubler(lst): return [num * 2 for num in lst] |
Хорошо, отлично, но зачем мне это нужно?
Списковые включения (генератор списка, list comprehensions) отлично подходят для случаев, когда нам нужно сохранить немного места в коде. Они также удобны в случаях, когда вам просто нужно быстро обработать списки, чтобы сэкономить время над рутинной работой с этим списком.
Они также очень полезны, если вы хотите больше узнать о функциональном программировании, но эту тему мы обсудим в будущем.
Применяем условие if в список
Давайте сделаем новую функцию, которая будет давать только длинные слова из списка. Скажем, каждое слово, которое состоит более чем из 5 букв, будет считаться длинным. Для начала пропишем их вручную.
def long_words(lst): words = [] for word in lst: if len(word) > 5: words.append(word) return words |
Мы создали переменную для хранения наших слов, применяем цикл над всеми словами в нашем списке, и проверяем длинну каждого слова. Если оно длиннее 5 букв, мы вносим слово в список, и затем, наконец, мы отсылаем список назад. Давайте попробуем.
long_words(['blog', 'Treehouse', 'Python', 'hi'])
возвращает ['Treehouse', 'Python']
. Это как раз то, чего мы и ожидали.
Хорошо, давайте перепишем это в списковое включение. Для начала, построим то, что мы и так знаем.
def long_words(lst): return [word for word in lst] |
Это возвращает нам все слова, не только те, которые длиннее 5 букв. Мы вносим условный оператор в конец цикла for.
def long_words(lst): return [word for word in lst if len(word) > 5] |
Итак, мы использовали всё то же условие if, но поместили его в конец спискового включения. Оно использует то же наименование переменной, которое мы используем для элементов в списке.
Хорошо, давайте опробуем эту версию long_words(['list', 'comprehension', 'Treehouse', 'Ken'])
возвращает ['comprehension', 'Treehouse']
.
Примеры
1. Возводим в квадрат все числа от 1 до 9. Применяем функцию range.
[x**2 for x in range(10)] |
Результат:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] |
2. Все цифры которые делятся на 5 без остатка, в диапазоне от 0 до 100.
[x for x in range(100) if x%5 == 0] |
Результат:
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95] |
3. Все цифры которые делятся на 3 и 6 без остатка, в диапазоне от 0 до 50.
[x for x in range(50) if x%3 == 0 and x%6 != 0] |
Результат:
[3, 9, 15, 21, 27, 33, 39, 45] |
4. Первая буква из каждого слова предложения.
phrase = «Тестовое сообщение из мира Python для сообщества.» print([w[0] for w in phrase.split()]) |
Результат:
[‘Т’, ‘с’, ‘и’, ‘м’, ‘P’, ‘д’, ‘с’] |
5. Заменяем букву А
в каждом слове на #
.
phrase = «АБАЖУР, АБАЗИНСКИЙ, АБАЗИНЫ, АББАТ, АББАТИСА, АББАТСТВО» print(».join([letter if letter != ‘А’ else ‘#’ for letter in phrase])) |
Результат:
#Б#ЖУР, #Б#ЗИНСКИЙ, #Б#ЗИНЫ, #ББ#Т, #ББ#ТИС#, #ББ#ТСТВО |
Итоги
Надеюсь это руководство помогло вам понять простой способ экономии кода , который вам нужно написать для получения конкретной готовой работы с вашими списками.
Старайтесь сохранять ваши списковые включения короткими, а условия if – простыми. Несложно разглядеть решение многих ваших проблем в списковых включениях и превратить их в огромный беспорядок.
Если это только распалило ваш аппетит, посмотрим, сможете ли вы разобраться со словарными включениями самостоятельно. Они используют конструкторы dict, {:} , но они довольно похожи. Вы также можете проработать установочные включения. Также ознакомьтесь с функциональным программированием в Python, если считаете себя готовым.
Больше примеров
- https://www.python.org/dev/peps/pep-0289/
- https://legacy.python.org/dev/peps/pep-0274/
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
Given a String comprising of many words separated by space, write a Python program to iterate over these words of the string.
Examples:
Input: str = “GeeksforGeeks is a computer science portal for Geeks”
Output: GeeksforGeeks is a computer science portal for GeeksInput: str = “Geeks for Geeks”
Output: Geeks for Geeks
Method 1: Using split() Using split() function, we can split the string into a list of words and is the most generic and recommended method if one wished to accomplish this particular task. But the drawback is that it fails in the cases in string contains punctuation marks.
Python3
test_string
=
"GeeksforGeeks is a computer science portal for Geeks"
print
(
"The original string is : "
+
test_string)
res
=
test_string.split()
print
(
"nThe words of string are"
)
for
i
in
res:
print
(i)
Output
The original string is : GeeksforGeeks is a computer science portal for Geeks The words of string are GeeksforGeeks is a computer science portal for Geeks
Time complexity: O(n)
Auxiliary Space: O(n)
Method 2: Using re.findall() In the cases which contain all the special characters and punctuation marks, as discussed above, the conventional method of finding words in a string using split can fail and hence requires regular expressions to perform this task. findall() function returns the list after filtering the string and extracting words ignoring punctuation marks.
Python3
import
re
test_string
=
"GeeksforGeeks is a computer science portal for Geeks !!!"
print
(
"The original string is : "
+
test_string)
res
=
re.findall(r
'w+'
, test_string)
print
(
"nThe words of string are"
)
for
i
in
res:
print
(i)
Output
The original string is : GeeksforGeeks is a computer science portal for Geeks !!! The words of string are GeeksforGeeks is a computer science portal for Geeks
Method 3: Using for loop and string slicing
Python3
test_string
=
"GeeksforGeeks is a computer science portal for Geeks"
print
(
"The original string is: "
+
test_string)
start
=
0
for
i
in
range
(
len
(test_string)):
if
test_string[i]
=
=
' '
:
print
(test_string[start:i])
start
=
i
+
1
print
(test_string[start:])
Output
The original string is: GeeksforGeeks is a computer science portal for Geeks GeeksforGeeks is a computer science portal for Geeks
This approach uses a for loop to iterate through the characters in the string and a variable to keep track of the starting index of the current word. When a space is encountered, the current word is printed and the starting index is updated to the next character. The last word in the string is printed outside the loop.
Time Complexity: O(n)
Auxiliary Space : O(n)
Method 4: Using the split() method with a regular expression
Use the split() method with a regular expression to split the string into words
Step-by-step approach:
- Initialize a list to store the words extracted from the string.
- Use the split() method with a regular expression to split the string into words.
- Iterate over the words and append them to the list.
- Print the list of words.
Follow the below steps to implement the above idea:
Python3
import
re
test_string
=
"GeeksforGeeks is a computer science portal for Geeks !!!"
print
(
"The original string is : "
+
test_string)
res
=
re.split(r
'W+'
, test_string)
words
=
[]
for
word
in
res:
if
word:
words.append(word)
print
(
"nThe words of string are"
)
for
word
in
words:
print
(word)
Output
The original string is : GeeksforGeeks is a computer science portal for Geeks !!! The words of string are GeeksforGeeks is a computer science portal for Geeks
Time complexity: O(n), where n is the length of the input string.
Auxiliary space: O(n), where n is the length of the input string.