Книга: Как устроен Python. Гид для разработчиков, программистов и интересующихся
Назад: 14. Контейнеры: списки, кортежи и множества
Дальше: 16. Словари

15. Итерации

Одна из стандартных идиом при работе с последовательностями — перебор содержимого последовательности. Например, вы можете отфильтровать один из элементов, применить к элементам функцию, вывести элементы и т.д. Для решения этой задачи можно воспользоваться цик­лом for. В следующем примере выводятся все строки из списка:

>>> for letter in ['c', 'a', 't']:

... print(letter)

c

a

t

 

>>> print(letter)

t

ПРИМЕЧАНИЕ

Обратите внимание: конструкция цикла for содержит двоеточие (:), за которым следует код с отступом (блок цикла for).

В цикле for Python создает новую переменную letter для хранения текущего элемента. Обратите внимание: в letter хранится не индекс, а строка. Python не очищает переменную после завершения цикла.

15.1. Перебор с индексом

В таких языках, как C, перебор в последовательностях ведется не по элементам последовательности, а по индексам. Используя индексы, вы можете извлекать элементы с указанными индексами. Ниже показан один из вариантов решения этой задачи с использованием встроенных функций Python range и len:

>>> animals = ["cat", "dog", "bird"]

>>> for index in range(len(animals)):

... print(index, animals[index])

0 cat

1 dog

2 bird

Приведенный выше фрагмент содержит код с душком: этот термин обычно подразумевает, что вы используете Python не так, как следовало бы. Обычно перебор в последовательностях выполняется для получения доступа к элементам последовательности, а не к индексам. Тем не менее в отдельных случаях индекс тоже бывает нужен. Python предоставляет встроенную функцию enumerate, с которой комбинация range и len становится излишней. Функция enumerate возвращает кортеж (индекс, элемент) для каждого элемента в последовательности:

>>> animals = ["cat", "dog", "bird"]

>>> for index, value in enumerate(animals):

... print(index, value)

0 cat

1 dog

2 bird

Так как кортеж содержит пару из индекса и значения, вы можете воспользоваться распаковкой кортежа для создания двух переменных, index и value, прямо в цикле for. Имена переменных должны разделяться запятой. Если длина кортежа совпадает с количеством переменных, включаемых в цикл for, Python создаст их за вас.

514581.png 

Рис. 15.1. Создание переменной в цикле for. Создается новая переменная letter; сначала она указывает на символ 'c', который выводится вызовом print. Затем цикл переходит на следующую итерацию, и переменная указывает на 'a'

514600.png 

Рис. 15.2. Цикл for продолжается, а после вывода 't' он завершается. В этот момент литерал списка уничтожается в ходе уборки мусора. Так как на 'c' и 'a' указывает только список, они тоже уничтожаются. Однако переменная letter продолжает указывать на 't'. Python не уничтожает эту переменную, и она продолжит существовать после завершения цикла for

15.2. Выход из цикла

Иногда бывает нужно прервать выполнение цикла преждевременно, до перебора всех элементов в цикле. Ключевое слово break прерывает ближайший внутренний цикл, в котором вы находитесь. Следующая программа суммирует числа до тех пор, пока не обнаружит отрицательное число. В этом случае выполнение цикла прерывается командой break:

>>> numbers = [3, 5, 9, -1, 3, 1]

>>> result = 0

>>> for item in numbers:

... if item < 0:

... break

... result += item

>>> print(result)

17

ПРИМЕЧАНИЕ

В строке

result += item

используется так называемое расширенное присваивание. Эта команда эквивалентна:

result = result + item

Расширенное присваивание выполняется чуть быстрее, так как выборка для переменной result выполняется всего один раз. Кроме того, команда получается более компактной и быстрее вводится.

ПРИМЕЧАНИЕ

Блок if внутри блока for снабжен отступом из восьми пробелов. Блоки могут быть вложенными, и каждый уровень должен иметь свой отступ.

15.3. Пропуск элементов в цикле

Другая стандартная идиома циклов — пропуск отдельных элементов при переборе. Если выполнение тела цикла for занимает некоторое время, а выполняться оно должно только для некоторых элементов последовательности, вам пригодится ключевое слово continue. Команда continue приказывает Python прервать обработку текущего элемента цикла и продолжить цикл от начала блока for со следующим значением в цикле.

В следующем примере суммируются все положительные числа из списка:

>>> numbers = [3, 5, 9, -1, 3, 1]

>>> result = 0

>>> for item in numbers:

... if item < 0:

... continue

... result = result + item

>>> print(result)

21

15.4. Оператор in может использоваться для проверки принадлежности

Мы использовали команду in в цикле for. В языке Python эта команда также может использоваться для проверки принадлежности. Если вы хотите узнать, содержит ли список заданный элемент, используйте коман­ду in для проверки:

>>> animals = ["cat", "dog", "bird"]

>>> 'bird' in animals

True

Если вам потребуется узнать индекс, используйте метод .index:

>>> animals.index('bird')

2

15.5. Удаление элементов из списков при переборе

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

Например, если вы захотите отфильтровать список имен так, чтобы в нем остался только элемент 'John' или 'Paul', делать это так было бы неправильно:

>>> names = ['John', 'Paul', 'George',

... 'Ringo']

>>> for name in names:

... if name not in ['John', 'Paul']:

... names.remove(name)

 

>>> print(names)

['John', 'Paul', 'Ringo']

Что произошло? Python предполагает, что списки не изменяются в процессе перебора. Добравшись до 'George', цикл удаляет имя из списка. Во внутренней реализации Python отслеживает текущий индекс цикла for. На этот момент в списке остаются только три элемента: 'John', 'Paul' и 'Ringo'. Однако цикл for думает, что текущей является позиция с индексом 3 (четвертый элемент), а четвертого элемента не существует, поэтому цикл останавливается, и элемент 'Ringo' остается на месте.

Существует два альтернативных решения для удаления элементов из списка в процессе перебора. В первом варианте удаляемые элементы отбираются при первом проходе по списку. Следующий цикл перебирает только те элементы, которые подлежат удалению (names_to_remove), и удаляет их из исходного списка (names):

>>> names = ['John', 'Paul', 'George',

... 'Ringo']

>>> names_to_remove = []

>>> for name in names:

... if name not in ['John', 'Paul']:

... names_to_remove.append(name)

 

>>> for name in names_to_remove:

... names.remove(name)

 

>>> print(names)

['John', 'Paul']

Другое решение — перебор по копии списка. Оно довольно легко реализуется конструкцией копирования среза [:], которая будет рассмотрена в главе, посвященной срезам:

>>> names = ['John', 'Paul', 'George',

... 'Ringo']

>>> for name in names[:]: # copy of names

... if name not in ['John', 'Paul']:

... names.remove(name)

 

>>> print(names)

['John', 'Paul']

15.6. Блок else

Цикл for также может содержать блок else. Любой код в блоке else будет выполнен в том случае, если цикл for не достиг команды break. Сле­дующий пример проверяет, являются ли числа из цикла положительными:

>>> positive = False

>>> for num in items:

... if num < 0:

... break

... else:

... positive = True

Команды continue не влияют на выполнение блока else.

Имя команды else выглядит несколько странно. Для цикла for она показывает, что была обработана вся последовательность. Блок else в цикле for часто применяется для обработки отсутствия элементов.

15.7. Циклы while

Python позволяет многократно выполнять блок кода, пока некоторое условие остается истинным. Такая конструкция называется циклом while, а для ее создания используется команда while. За циклом while следует выражение, результат которого равен True или False, а за выражением идет двоеточие. Помните, что следует за двоеточием (:) в Python? Да, блок кода с отступом. Этот блок продолжит выполняться, пока результат выражения остается равным True. В программе может легко возникнуть бесконечный цикл.

Бесконечные циклы обычно нежелательны, потому что ваша программа «зависает» в цикле без возможности выхода. Впрочем, у правила есть исключения: например, сервер в бесконечном цикле принимает и обрабатывает запросы. Другое исключение, встречающееся в коде Python более высокого уровня, — бесконечный генератор. Генератор ведет себя как отложенный список, который создает значения только тогда, когда они будут задействованы в переборе. Если вы знакомы с обработкой потоков, генератор можно рассматривать как поток. (Генераторы в этой книге не рассматриваются, но я опишу их в книге более высокого уровня.)

Как правило, если у вас имеется объект, поддерживающий перебор, для перебора элементов используется цикл for. Циклы while используются при отсутствии простого доступа к объекту, поддерживающему перебор.

Типичный пример использования цикла while — обратный отсчет:

>>> n = 3

>>> while n > 0:

... print(n)

... n = n - 1

3

2

1

Для выхода из цикла while также может использоваться команда break:

>>> n = 3

>>> while True:

... print(n)

... n = n - 1

... if n == 0:

... break

15.8. Итоги

В этой главе рассматривается использование циклов for для перебора элементов последовательности. Вы видели, что в цикле можно вести перебор по спискам; также возможен перебор по строкам, кортежам, словарям и другим структурам данных. Более того, вы можете определять собственные классы, поддерживающие перебор в циклах for, реализуя метод .__iter__.

Цикл for создает переменную при переборе. Эта переменная не уничтожается после цикла, а продолжает существовать. Если цикл for выполняется внутри функции, переменная будет уничтожена при выходе из функции.

Также в этой главе была представлена функция enumerate. Функция возвращает последовательность кортежей (пар «индекс, значение») для переданной последовательности. Если вам понадобится получить при переборе как индекс, так и значение, используйте enumerate.

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

15.9. Упражнения

1. Создайте список с именами друзей и коллег. Вычислите среднюю длину имен в списке.

2. Создайте список с именами друзей и коллег. Проведите поиск имени John в списке в цикле for. Если имя не найдено, выведите соответствующее сообщение (подсказка: используйте else).

3. Создайте список кортежей из имени, фамилии и возраста ваших друзей и коллег. Если возраст неизвестен, занесите значение None. Вычислите средний возраст, пропустив все значения None. Выведите каждое имя, за которым следует строка Old (возраст выше среднего) или Young (возраст ниже среднего).

Назад: 14. Контейнеры: списки, кортежи и множества
Дальше: 16. Словари