Справочник по Python · модуль 3 · списки и циклы
Глава 3.7
Вложенные циклы
(nested loops)
Во вложенной конструкции полный внутренний цикл выполняется заново для каждого значения внешнего. Так обрабатывают таблицы, матрицы и пары элементов.
- Категория
- Циклы и двумерные данные
- Уровень
- Начальный
- Связанные темы
- for, range(), вложенные списки
- Зачем это знать
- Обрабатывать строки таблиц и сочетания значений
§1Общая схема
for outer in outer_values: for inner in inner_values: action
Внутренний for находится в теле внешнего. Поэтому каждый новый outer запускает весь перебор inner сначала.
§2Пошаговое выполнение
for row in range(3): for column in range(3): print(row, column)
0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2
При row = 0 внутренний цикл получает 0, 1, 2. Затем row становится равен 1, и внутренний диапазон снова начинается с нуля.
§3Количество повторений
Если внешний цикл делает N повторений, а внутренний — M для каждого внешнего, самое глубокое действие выполняется N × M раз.
3 внешних × 3 внутренних = 9 вызовов print() 4 внешних × 5 внутренних = 20 действий
§4Таблица умножения
for row in range(1, 6): for column in range(1, 6): print(row * column, end=" ") print()
1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
print() без аргументов выровнен с внутренним циклом, поэтому выполняется после каждой готовой строки.
§5Матрица
Матрицу можно представить списком строк. Внешний цикл получает строку, внутренний — элементы этой строки.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] for row in matrix: for element in row: print(element)
§6Поиск совпадений
Вложенные циклы позволяют сравнить каждый элемент первого списка с каждым элементом второго.
first = [1, 2, 3] second = [2, 3, 4] for left in first: for right in second: if left == right: print("Совпадение:", left)
Совпадение: 2 Совпадение: 3
§7break во вложенном цикле
break завершает только ближайший цикл — тот, внутри которого написан.
for outer in range(3): for inner in range(5): if inner == 2: break print(outer, inner)
0 0 0 1 1 0 1 1 2 0 2 1
§8Как выйти сразу из обоих
Раз break завершает только ближайший цикл, возникает вопрос: как остановить перебор целиком, если нужное найдено? Готовой конструкции для этого в Python нет — есть два приёма.
Первый — флаг. Результат сохраняют в переменную и после внутреннего цикла проверяют её.
matrix = [[1, 2], [3, 4], [5, 6]] found = None for row in matrix: for value in row: if value == 4: found = value break if found is not None: break print(found)
4
Второй break стоит уже в теле внешнего цикла и потому завершает его. Обратите внимание на отступ: он на два уровня меньше первого.
Второй приём — вынести перебор в функцию и выйти через return. Он завершает функцию целиком, а значит и оба цикла сразу.
def find(matrix, target): for row in matrix: for value in row: if value == target: return value return None print(find([[1, 2], [3, 4]], 4)) print(find([[1, 2], [3, 4]], 99))
4 None
Второй вариант читается лучше: нет ни флага, ни повторной проверки, а последний return None явно описывает случай «ничего не нашлось». Функции разбираются в главе 6.2.
§9continue во вложенном цикле
continue пропускает текущий шаг ближайшего цикла. Внешнее значение при этом не меняется.
for outer in range(3): for inner in range(3): if inner == 1: continue print(outer, inner)
§10Сложность
Два полных цикла по n элементов выполняют около n² сравнений. Для 100 элементов это 10 000, а для 10 000 — уже 100 000 000.
Вложение удобно и понятно для небольших таблиц. При больших наборах проверьте, можно ли заменить полный перебор множеством, словарём или другим алгоритмом.
§11Частые ошибки
| Что написано | Что произойдёт | Как правильно |
|---|---|---|
внутренний for без отступа | получатся два независимых цикла | поместить внутренний цикл в тело внешнего |
| ожидать, что внутренний цикл продолжится с прошлого значения | расчёт шагов будет неверным | помнить: он начинается заново для каждого внешнего значения |
break внутри внутреннего цикла | внешний цикл продолжит работу | отдельно управлять выходом из обоих уровней |
перепутать отступ итогового print() | строки таблицы объединятся или будут разбиты неверно | выровнять его после внутреннего цикла |
| полный двойной перебор больших списков | число операций быстро растёт | оценить N × M до запуска |
§12Проверьте себя
Сколько раз выполнится действие при диапазонах 4 и 5?
4 × 5 = 20 раз.
Какой цикл завершит break внутри внутреннего тела?
Только ближайший внутренний цикл.
Почему внутренний цикл запускается повторно?
Потому что его полный перебор является телом каждой итерации внешнего цикла.
§13Шпаргалка
for row in rows: for item in row:N × Mзавершает ближайший циклпропускает шаг ближайшегоИтог главы
Для каждого значения внешнего цикла внутренний цикл проходит все свои значения. Глубокое действие выполняется N × M раз. break и continue управляют только ближайшим циклом.