Вложенные циклы в Python

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


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

Хотя во вложенных циклах нет ничего особенного, новичку они могут показаться немного пугающими или многословными.

Что такое вложенные циклы?

Термин “вложенный” широко используется в программировании. По определению, слово “вложенный” означает, что объект помещается внутри другого объекта того же типа.

В Python внутри цикла можно поместить любой допустимый код. В том числе и другой цикл.

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

Скачивайте книги ТОЛЬКО на русском языке у нас в телеграм канале: PythonBooksRU

Как работают вложенные циклы?

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

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

for element in sequence1:
   for element in sequence2:
      # тело внутреннего цикла 
   # тело внешнего цикла 

Каждая итерация внешнего цикла заставляет внутренний цикл выполнить все свои итерации. Внешний цикл не выполняется до завершения внутреннего цикла.

Поясним: вложенными могут быть не только циклы for. Вы можете размещать циклы while внутри циклов while, циклы while внутри циклов for и т.д. Вложенный цикл – это цикл, внутри которого находится как минимум один цикл.

Типичным сценарием использования вложенного цикла является работа с многомерными данными, такими как списки списков и т.п.

Давайте рассмотрим несколько простых примеров вложенных циклов.

Пример 1. Вложенные циклы for

Давайте используем вложенный цикл for, чтобы вывести таблицу умножения первых 10 чисел.

for i in range(1, 11):
    for j in range(1, 11):
        print(i * j, end=" ")
    print()

Вывод:

1 2 3 4 5 6 7 8 9 10 
2 4 6 8 10 12 14 16 18 20 
3 6 9 12 15 18 21 24 27 30 
4 8 12 16 20 24 28 32 36 40 
5 10 15 20 25 30 35 40 45 50 
6 12 18 24 30 36 42 48 54 60 
7 14 21 28 35 42 49 56 63 70 
8 16 24 32 40 48 56 64 72 80 
9 18 27 36 45 54 63 72 81 90 
10 20 30 40 50 60 70 80 90 100

Давайте рассмотрим подробнее, как работает эта программа:

  1. Внешний цикл перебирает числа от 1 до 10 и сохраняет текущее число во временной переменной i. Таким образом, на первой итерации i = 1, на второй i = 2 и так далее.
  2. Внутренний цикл также перебирает числа от 1 до 10. Внутренний цикл хранит номер текущей итерации в переменной j.
  3. За каждую итерацию внешнего цикла внутренний цикл будет выполняться полностью, то есть 10 раз.
  4. Так, например, во время первой итерации внешнего цикла i = 1, а j переходит от 1 к 10. Во время второй итерации i = 2, а j снова переходит от 1 к 10, и так далее.
  5. В результате получается таблица умножения, в которой каждое число 1…10 умножается на 1…10.
Схема вложенного цикла for

Кстати, если вы хотите красиво отформатировать умножение, чтобы числа выровнялись в каждом столбце, вы можете преобразовать результат умножения в строку и использовать метод str.ljust().

Вот как это выглядит в коде:

for i in range(1, 11):
    for j in range(1, 11):
        print(f"{i * j}".ljust(3), end=" ")
    print()

Вывод:

1   2   3   4   5   6   7   8   9   10  
2   4   6   8   10  12  14  16  18  20  
3   6   9   12  15  18  21  24  27  30  
4   8   12  16  20  24  28  32  36  40  
5   10  15  20  25  30  35  40  45  50  
6   12  18  24  30  36  42  48  54  60  
7   14  21  28  35  42  49  56  63  70  
8   16  24  32  40  48  56  64  72  80  
9   18  27  36  45  54  63  72  81  90  
10  20  30  40  50  60  70  80  90  100 

Пример 2. Вложенные циклы while

Для полноты картины повторим приведенный выше пример, используя вложенный цикл while. Смысл этого примера в том, чтобы показать, что цикл while тоже можно поместить внутри другого цикла.

Вот код:

i = 1
j = 1

while i <= 10:
    while j <= 10:
        print(i * j, end = " ")
        j += 1
    j = 1
    print()
    i += 1

Вывод:

1 2 3 4 5 6 7 8 9 10 
2 4 6 8 10 12 14 16 18 20 
3 6 9 12 15 18 21 24 27 30 
4 8 12 16 20 24 28 32 36 40 
5 10 15 20 25 30 35 40 45 50 
6 12 18 24 30 36 42 48 54 60 
7 14 21 28 35 42 49 56 63 70 
8 16 24 32 40 48 56 64 72 80 
9 18 27 36 45 54 63 72 81 90 
10 20 30 40 50 60 70 80 90 100 

Вот иллюстрация частей вложенного цикла while, приведенного выше:

Схема вложенного цикла while

Как управлять потоком вложенного цикла?

В Python потоком или циклом можно управлять. Двумя основными операторами управления потоком в Python являются:

  • break. Оператор break завершает цикл.
  • continue. Оператор continue завершает текущую итерацию цикла и переходит к следующей.

Давайте подробнее рассмотрим, как эти операторы работают с вложенными циклами в Python.

Как прервать вложенный цикл?

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

Давайте рассмотрим простой пример использования оператора break в действии:

target = 3

for number in range(10):
    print(number)
    if number == target:
        break

Вывод:

0
1
2
3

Здесь цикл завершается при достижении числа 3.

Во вложенном цикле оператор break завершает внутренний цикл, но продолжает выполнение внешнего цикла. Поэтому, если вы вызываете оператор break во внутреннем цикле вложенного цикла, то он останавливает не весь цикл, а только его внутреннюю часть.

Например, напечатаем полупирамиду из звездочек так, чтобы количество звездочек было номером строки в фигуре, если читать сверху вниз:

for i in range(1, 11):
    for j in range(1, 11):
        if j - i > 0:
            break
        print("*", end=" ")
    print()

Вывод:

* 
* * 
* * * 
* * * * 
* * * * * 
* * * * * * 
* * * * * * * 
* * * * * * * * 
* * * * * * * * * 
* * * * * * * * * *

В таком вложенном цикле можно считать, что i – это номер строки, а j – номер столбца.

Здесь оператор break завершает внутренний цикл, если j - i меньше 0. Другими словами, вы прекращаете выполнение внутреннего цикла, если количество звездочек (*) больше номера строки.

Как продолжить вложенный цикл?

В Python оператор continue позволяет пропустить “остаток” итерации цикла и начать следующую итерацию.

Этот оператор завершает не весь цикл, а только текущую итерацию. Оператор continue полезен, если нет причин продолжать текущую итерацию цикла. Например, если вы хотите выполнять действия, основанные только на условии, вы можете использовать оператор continue, чтобы пропустить эти действия.

Оператор continue можно использовать во вложенном цикле так же, как и в одиночном.

  1. Если вы вызываете оператор continue во внутреннем цикле, то текущая итерация останавливается и начинается следующая итерация внутреннего цикла.
  2. Если вызвать оператор continue перед внутренним циклом в теле внешнего цикла, то итерация внешнего цикла переходит к следующей итерации, пропуская внутренний цикл.

Например, напечатаем перевернутую полупирамиду из звездочек так, чтобы количество звездочек было номером строки в фигуре, если читать снизу вверх:

for i in range(1, 11):
    for j in range(1, 11):
        if i + j > 11:
            continue
        print("*", end=" ")
    print()

Вывод:

* * * * * * * * * * 
* * * * * * * * * 
* * * * * * * * 
* * * * * * * 
* * * * * * 
* * * * * 
* * * * 
* * * 
* * 
* 

Здесь оператор continue переводит внутренний цикл на следующую итерацию, если i + j больше 11. Другими словами, внутренний цикл пропускает печать звездочек (*), если номер строки плюс номер столбца больше 11.

Однострочные вложенные циклы с List Comprehensions

В Python циклы for можно сделать более компактными с помощью list comprehensions (генераторов списков). Таким образом можно создать аккуратный однострочник, а не разворачивать цикл на несколько строк кода.

Вы также можете создать вложенный list comprehension. Стоит ли это делать – вопрос спорный. Некоторые утверждают, что это делает код более компактным и более легким для чтения. Другие говорят, что это только усложняет код.

В общем, создавая вложенные генераторы списков, будьте осторожны. Из-за многословного и нечитабельного выражения качество кода может пострадать. Поэтому пишите вложенные list comprehensions только тогда, когда это точно улучшит код!

mul_tab = [[i * j for  in range(1, 11)] for j in range(1, 11)]

for row in mul_tab:
    print(row)

Вывод:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
[3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60]
[7, 14, 21, 28, 35, 42, 49, 56, 63, 70]
[8, 16, 24, 32, 40, 48, 56, 64, 72, 80]
[9, 18, 27, 36, 45, 54, 63, 72, 81, 90]
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Как превратить вложенный цикл for во вложенный list comprehension?

В предыдущем разделе вы видели пример создания вложенного генератора списка из вложенного цикла for. Но из приведенного примера неясно, как именно это делается.

Вот схема создания вложенных генераторов списков из вложенных циклов for:

[expression for outer_loop for inner_loop]

Порядок преобразования может сбить вас с толку, потому что внешний цикл происходит во “внутренней части” list comprehension, а внутренний цикл – во “внешней”.

Для лучшего понимания вот иллюстрация преобразования вложенного цикла for во вложенный генератор списка.

Заключение

Сегодня вы узнали, как работают вложенные циклы в Python.

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

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

Спасибо за прочтение. Успешного кодинга!

Перевод статьи Artturi Jalli “Nested Loops in Python: A Complete Guide”.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *