Python "for" циклы (определенная итерация)

Из этого туториала Вы узнаете, как выполнить определенную итерацию с помощью forцикла Python .

В предыдущем руководстве этой вводной серии вы узнали следующее:

Повторяющееся выполнение одного и того же блока кода снова и снова называется итерацией .
Есть два типа итераций:
Определенная итерация, в которой количество повторений указывается заранее явно
Бесконечная итерация, при которой блок кода выполняется до тех пор, пока не будет выполнено какое-либо условие.
В Python неопределенная итерация выполняется с помощью whileцикла.
Вот что вы расскажете в этом уроке:

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

Затем вы узнаете об итерациях и итераторах , двух концепциях, которые составляют основу определенной итерации в Python.

Наконец, вы свяжете все это вместе и узнаете о forциклах Python .

Обзор определенных итераций в программировании

Циклы с определенными итерациями часто называют forциклами, поскольку forэто ключевое слово используется для их представления почти во всех языках программирования, включая Python.

Исторически языки программирования предлагали несколько разновидностей forциклов. Они кратко описаны в следующих разделах.

Цикл числового диапазона

Самый простой forцикл - это простой оператор числового диапазона с начальным и конечным значениями. Точный формат зависит от языка, но обычно выглядит примерно так:

for i = 1 to 10
    

Здесь тело цикла выполняется десять раз. Переменная i принимает значение 1на первой итерации, 2на втором, и так далее. Этот вид forцикла используется в языках BASIC, Algol и Pascal.

Цикл с тремя выражениями

Другая форма forцикла, популярная в языке программирования C, состоит из трех частей:

Инициализация
Выражение, определяющее конечное условие
Действие, выполняемое в конце каждой итерации.
Этот тип цикла имеет следующий вид:

for (i = 1; i <= 10; i++)
    

Этот цикл интерпретируется следующим образом:

Инициализировать iв 1.
Продолжайте делать петли до тех пор, пока i <= 10.
Увеличение iна 1после каждой итерации цикла.
forЦиклы с тремя выражениями популярны, потому что выражения, указанные для трех частей, могут быть почти любыми, так что это дает немного больше гибкости, чем простая форма числового диапазона, показанная выше. Эти forциклы также представлены в языках C ++ , Java, PHP и Perl.

Цикл на основе коллекции или итератора

Этот тип цикла выполняет итерацию по коллекции объектов, а не указывает числовые значения или условия:

for i in 
    

Каждый раз при прохождении цикла переменная iпринимает значение следующего объекта в . Этот тип forцикла, пожалуй, самый общий и абстрактный. Perl и PHP также поддерживают этот тип цикла, но он вводится ключевым словом foreachвместо for.

Python для цикла

Из перечисленных выше типов циклов Python реализует только последнюю итерацию на основе коллекции. На первый взгляд это может показаться грубым делом, но будьте уверены, что реализация определенной итерации в Python настолько универсальна, что вы не почувствуете себя обманутым!

Вскоре вы forподробно раскроете внутренности цикла Python . А пока начнем с быстрого прототипа и примера, просто для ознакомления.

forЦикл Python выглядит так:

for  in :
    

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

Вот типичный пример:

a = ['foo', 'bar', 'baz']
>>> for i in a:
...     print(i)
...
foo
bar
baz

В этом примере - это список a, а - переменная i. Каждый раз через петлю, iберет на последовательный элементе a, так что print()отображает значения 'foo', 'bar'и 'baz', соответственно. Такой forцикл - это питонический способ обработки элементов в итеративном режиме.

Но что такое итерация? Перед forдальнейшим изучением циклов будет полезно более глубоко изучить, что такое итерируемые объекты в Python.

Итерируемые объекты

В Python итерация означает, что объект можно использовать в итерации. Этот термин используется как:

Прилагательное: объект можно описать как повторяющийся.
Существительное: объект можно охарактеризовать как повторяющийся.
Если объект является итеративным, его можно передать встроенной функции Python iter(), которая возвращает нечто, называемое итератором . Да, терминология становится немного повторяющейся. Повесить там. В конце концов, все получается.

Каждый из объектов в следующем примере является итерируемым и возвращает некоторый тип итератора при передаче в iter():

>>> iter('foobar')                             # String


>>> iter(['foo', 'bar', 'baz'])                # List


>>> iter(('foo', 'bar', 'baz'))                # Tuple


>>> iter({'foo', 'bar', 'baz'})                # Set


>>> iter({'foo': 1, 'bar': 2, 'baz': 3})       # Dict

С другой стороны, эти типы объектов не повторяются:

>>> iter(42)                                   # Integer
Traceback (most recent call last):
  File "", line 1, in 
    iter(42)
TypeError: 'int' object is not iterable

>>> iter(3.1)                                  # Float
Traceback (most recent call last):
  File "", line 1, in 
    iter(3.1)
TypeError: 'float' object is not iterable

>>> iter(len)                                  # Built-in function
Traceback (most recent call last):
  File "", line 1, in 
    iter(len)
TypeError: 'builtin_function_or_method' object is not iterable

Все типы данных, с которыми вы столкнулись до сих пор, которые являются типами коллекций или контейнеров, являются итеративными. К ним относятся типы string , list , tuple , dict , set и frozenset .

Но это ни в коем случае не единственные типы, которые можно перебирать. Многие объекты, встроенные в Python или определенные в модулях, предназначены для итерации. Например, открытые файлы в Python можно повторять. Как вы скоро увидите в учебнике по файловому вводу-выводу, итерация по открытому файловому объекту считывает данные из файла.

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

Итераторы

Хорошо, теперь вы знаете, что означает возможность итерации объекта, и знаете, как использовать его iter()для получения итератора. Что вы можете с ним делать, если у вас есть итератор?

Итератор - это, по сути, производитель значений, который выдает последовательные значения из связанного с ним итеративного объекта. Встроенная функция next()используется для получения следующего значения из итератора.

Вот пример с использованием того же списка, что и выше:

>>> a = ['foo', 'bar', 'baz']

>>> itr = iter(a)
>>> itr


>>> next(itr)
'foo'
>>> next(itr)
'bar'
>>> next(itr)
'baz'

В этом примере a- это повторяемый список и itrсвязанный с ним итератор, полученный с помощью iter(). Каждый next(itr)вызов получает следующее значение из itr.

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

Что происходит, когда в итераторе заканчиваются значения? Сделаем еще один next()вызов итератору выше:

>>> next(itr)
Traceback (most recent call last):
  File "", line 1, in 
    next(itr)
StopIteration

Если все значения от итератора уже были возвращены, последующий next()вызов вызывает StopIterationисключение. Любые дальнейшие попытки получить значения от итератора потерпят неудачу.

Вы можете получать значения от итератора только в одном направлении. Вы не можете вернуться назад. Нет prev()функции. Но вы можете определить два независимых итератора на одном итерируемом объекте:

>>> a
['foo', 'bar', 'baz']

>>> itr1 = iter(a)
>>> itr2 = iter(a)

>>> next(itr1)
'foo'
>>> next(itr1)
'bar'
>>> next(itr1)
'baz'

>>> next(itr2)
'foo'

Даже если итератор itr1уже находится в конце списка, itr2он все еще находится в начале. Каждый итератор поддерживает собственное внутреннее состояние, независимое от другого.

Если вы хотите получить сразу все значения из итератора, вы можете использовать встроенную list()функцию. Среди других возможных применений он list()принимает итератор в качестве аргумента и возвращает список, состоящий из всех значений, выданных итератором:

>>> a = ['foo', 'bar', 'baz']
>>> itr = iter(a)
>>> list(itr)
['foo', 'bar', 'baz']

Аналогичным образом , встроенные tuple()и set()функции возвращают кортеж и набор, соответственно, из всех значений AN урожайность итератора:

>>> a = ['foo', 'bar', 'baz']

>>> itr = iter(a)
>>> tuple(itr)
('foo', 'bar', 'baz')

>>> itr = iter(a)
>>> set(itr)
{'baz', 'foo', 'bar'}

Необязательно делать это привычкой. Отчасти элегантность итераторов заключается в том, что они «ленивы». Это означает, что когда вы создаете итератор, он не генерирует все элементы, которые он может дать в этот момент. Он ждет, пока вы их попросите next(). Элементы не создаются, пока они не будут запрошены.

Когда вы используете list(), tuple()или что-то подобное, вы заставляете итератор генерировать все свои значения сразу, чтобы их все можно было вернуть. Если общее количество объектов, возвращаемых итератором, очень велико, это может занять много времени.

Фактически, в Python можно создать итератор, который возвращает бесконечную серию объектов, используя функции генератора и itertools. Если вы попытаетесь получить сразу все значения из бесконечного итератора, программа зависнет .

Внутренности для петли Python

Теперь вы познакомились со всеми концепциями, необходимыми для полного понимания того, как работает forцикл Python . Прежде чем продолжить, давайте рассмотрим соответствующие термины:
Срок Смысл
Итерация Процесс перебора объектов или элементов в коллекции
Итерабельный Объект (или прилагательное, используемое для описания объекта), который можно повторять.
Итератор Объект, который производит последовательные элементы или значения из связанного с ним итеративного объекта.
iter() Встроенная функция, используемая для получения итератора из итерируемого
Теперь снова рассмотрим простой forцикл, представленный в начале этого урока:

>>> a = ['foo', 'bar', 'baz']
>>> for i in a:
...     print(i)
...
foo
bar
baz

Итерации по словарю

Ранее вы видели, что итератор можно получить из словаря с помощью iter(), поэтому вы знаете, что словари должны быть итеративными. Что происходит, когда вы просматриваете словарь? Посмотрим:

>>> d = {'foo': 1, 'bar': 2, 'baz': 3}
>>> for k in d:
...     print(k)
...
foo
bar
baz

Как видите, когда forцикл выполняет итерацию по словарю , переменная цикла присваивается ключам словаря.

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

>>> for k in d:
...     print(d[k])
...
1
2
3

Вы также можете перебирать значения словаря напрямую, используя .values():

>>> for v in d.values():
...     print(v)
...
1
2
3

Фактически, вы можете перебирать как ключи, так и значения словаря одновременно. Это потому, что переменная forцикла не ограничивается одной переменной. Это также может быть кортеж, и в этом случае присваивания выполняются из элементов в итерируемом объекте с использованием упаковки и распаковки, как и в случае с оператором присваивания:

>>> i, j = (1, 2)
>>> print(i, j)
1 2

>>> for i, j in [(1, 2), (3, 4), (5, 6)]:
...     print(i, j)
...
1 2
3 4
5 6

Как отмечалось в руководстве по словарям Python , метод словаря .items()фактически возвращает список пар ключ / значение в виде кортежей:

>>> d = {'foo': 1, 'bar': 2, 'baz': 3}

>>> d.items()
dict_items([('foo', 1), ('bar', 2), ('baz', 3)])

Таким образом, Python-способ перебора словаря с доступом как к ключам, так и к значениям выглядит так:

>>> d = {'foo': 1, 'bar': 2, 'baz': 3}
>>> for k, v in d.items():
...     print('k =', k, ', v =', v)
...
k = foo , v = 1
k = bar , v = 2
k = baz , v = 3

range()Функция

В первом разделе этого руководства вы видели тип forцикла, называемый циклом числового диапазона , в котором указываются начальное и конечное числовые значения. Хотя эта форма forцикла не встроена непосредственно в Python, к ней легко добраться.

Например, если вы хотите перебрать значения от 0до 4, вы можете просто сделать это:

>>> for n in (0, 1, 2, 3, 4):
...     print(n)
...
0
1
2
3
4

Это решение не так уж и плохо, когда есть всего несколько цифр. Но если бы диапазон чисел был намного больше, это быстро стало бы утомительно.

К счастью, Python предоставляет лучший вариант - встроенную range()функцию, которая возвращает итерацию, которая дает последовательность целых чисел.

range()возвращает итерацию, которая возвращает целые числа, начиная с 0, но не включая :

>>> x = range(5)
>>> x
range(0, 5)
>>> type(x)

Обратите внимание, что range()возвращает объект класса range, а не список или кортеж значений. Поскольку rangeобъект является итерируемым, вы можете получить значения, перебирая их с помощью forцикла:

>>> for n in x:
...     print(n)
...
0
1
2
3
4

Вы также можете получить сразу все значения с помощью list()или tuple(). В сеансе REPL это может быть удобным способом быстро отобразить значения:

>>> list(x)
[0, 1, 2, 3, 4]

>>> tuple(x)
(0, 1, 2, 3, 4)

Однако, когда range()он используется в коде, который является частью более крупного приложения, это обычно считается плохой практикой для использования list()или tuple()таким образом. Подобно итераторам, rangeобъекты «ленивы» - значения в указанном диапазоне не генерируются, пока они не будут запрошены. Использование list()или tuple()на rangeобъекте приводит к одновременному возврату всех значений. Это редко бывает необходимо, и если список будет длинным, это может привести к потере времени и памяти.

range(, , )возвращает итерацию, которая возвращает целые числа, начиная с , до, но не включая . Если указано, указывает величину пропуска между значениями (аналогично значению шага, используемому для нарезки строк и списков):

>>> list(range(5, 20, 3))
[5, 8, 11, 14, 17]

Если не указан, по умолчанию используется 1:

>>> list(range(5, 10, 1))
[5, 6, 7, 8, 9]
>>> list(range(5, 10))
[5, 6, 7, 8, 9]

Все указанные параметры range()должны быть целыми числами, но любой из них может быть отрицательным. Естественно, если больше , должно быть отрицательным (если вам нужны какие-либо результаты):

>>> list(range(-5, 5))
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]

>>> list(range(5, -5))
[]
>>> list(range(5, -5, -1))
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]

Заключение

В этом руководстве представлен forцикл, рабочая лошадка определенной итерации в Python.

Вы также узнали о внутренней работе итерируемых и итераторов , два важных типов объектов, лежащих в основе определенной итерации, но и занимает видное место в широком спектре другого кода Python.

В следующих двух руководствах этой вводной серии вы немного переключитесь и исследуете, как программы Python могут взаимодействовать с пользователем посредством ввода с клавиатуры и вывода на консоль.