Циклы Python "while" (бесконечная итерация)
Оглавление
- Цикл while
- Выражения break и continue в Python
- Клауза else
- Бесконечные циклы
- Вложенные циклы while
- Однострочные циклы while
- Заключение
Итерация означает выполнение одного и того же блока кода снова и снова, потенциально много раз. Структура программирования, реализующая итерацию, называется loop.
В программировании существует два типа итерации - неопределенная и определенная:
-
При бесконечной итерации количество раз выполнения цикла не задается заранее. Скорее, обозначенный блок выполняется многократно до тех пор, пока выполняется некоторое условие.
-
При бесконечной итерации количество выполнений обозначенного блока задается явно в момент запуска цикла.
В этом уроке вы узнаете:
- Узнайте о цикле
while
, управляющей структуре Python, используемой для неограниченной итерации - Узнайте, как преждевременно выйти из цикла или итерации цикла
- Исследуйте бесконечные циклы
Когда вы закончите, вы должны хорошо понимать, как использовать неопределенную итерацию в Python.
Цикл while
Давайте посмотрим, как оператор while
в Python используется для построения циклов. Мы начнем с простого и будем приукрашивать по ходу дела.
Формат простейшего цикла while
показан ниже:
while <expr>:
<statement(s)>
<statement(s)>
представляет собой блок для повторного выполнения, часто называемый телом цикла. Он обозначается с отступом, как и в операторе if.
Помните: Все управляющие структуры в Python используют отступы для определения блоков. См. обсуждение группировки операторов в предыдущем уроке для ознакомления.
Управляющее выражение, <expr>
, обычно включает одну или несколько переменных, которые инициализируются перед началом цикла, а затем изменяются в теле цикла.
Когда встречается цикл while
, <expr>
сначала оценивается в булевом контексте. Если оно истинно, то выполняется тело цикла. Затем снова проверяется <expr>
, и если оно по-прежнему истинно, тело цикла выполняется снова. Так продолжается до тех пор, пока <expr>
не станет ложным, после чего выполнение программы переходит к первому оператору за пределами тела цикла.
Рассмотрите этот цикл:
1 >>> n = 5
2 >>> while n > 0:
3 ... n -= 1
4 ... print(n)
5 ...
6 4
7 3
8 2
9 1
10 0
Вот что происходит в этом примере:
-
n
изначально является5
. Выражение в заголовке оператораwhile
в строке 2 равноn > 0
, что является истиной, поэтому тело цикла выполняется. Внутри тела цикла в строке 3 значениеn
уменьшается на1
до4
, а затем выводится на печать. -
После завершения тела цикла выполнение программы возвращается в начало цикла в строке 2, и выражение оценивается снова. Оно все еще истинно, поэтому тело цикла выполняется снова, и печатается
3
. -
Так продолжается до тех пор, пока
n
не станет0
. В этот момент, когда выражение проверяется, оно оказывается ложным, и цикл завершается. Выполнение возобновится с первого оператора, следующего за телом цикла, но в данном случае его нет.
Обратите внимание, что управляющее выражение цикла while
проверяется первым, прежде чем произойдет все остальное. Если оно равно false, тело цикла вообще не будет выполнено:
>>> n = 0
>>> while n > 0:
... n -= 1
... print(n)
...
В приведенном выше примере, когда встречается цикл, n
становится 0
. Управляющее выражение n > 0
уже равно false, поэтому тело цикла никогда не выполнится.
Вот еще один цикл while
, в котором используется не числовое сравнение, а список:
>>> a = ['foo', 'bar', 'baz']
>>> while a:
... print(a.pop(-1))
...
baz
bar
foo
Когда список оценивается в булевом контексте, он является истинным, если в нем есть элементы, и ложным, если он пуст. В данном примере a
истинен до тех пор, пока в нем есть элементы. Когда все элементы будут удалены методом .pop()
и список станет пустым, a
станет ложным, и цикл завершится.
Операторы break
и continue
В каждом примере, который вы видели до сих пор, на каждой итерации выполняется все тело цикла while
. Python предоставляет два ключевых слова, которые преждевременно завершают итерацию цикла:
-
Оператор Python
break
немедленно завершает цикл полностью. Программа переходит к первому оператору, следующему за телом цикла. -
Оператор Python
continue
немедленно завершает текущую итерацию цикла. Выполнение переходит в начало цикла, и управляющее выражение переоценивается, чтобы определить, будет ли цикл выполняться снова или завершится.
Различие между break
и continue
продемонстрировано на следующей диаграмме:
Вот файл сценария под названием break.py
, который демонстрирует оператор break
:
1 n = 5
2 while n > 0:
3 n -= 1
4 if n == 2:
5 break
6 print(n)
7 print('Loop ended.')
Запуск break.py
из интерпретатора командной строки приводит к следующему результату:
Командная строка Windows
C:\Users\john\Documents>python break.py
4
3
Loop ended.
Когда n
становится 2
, выполняется оператор break
. Цикл полностью завершается, и выполнение программы переходит к оператору print()
в строке 7.
Примечание: Если вы программируете на C, C++, Java или JavaScript, то вам может быть интересно, где в Python находится цикл do-while. Плохая новость заключается в том, что в Python нет конструкции do-while. Но хорошая новость заключается в том, что вы можете использовать цикл while
с оператором break
, чтобы имитировать его.
Следующий сценарий, continue.py
, идентичен, за исключением оператора continue
на месте break
:
1 n = 5
2 while n > 0:
3 n -= 1
4 if n == 2:
5 continue
6 print(n)
7 print('Loop ended.')
Вывод continue.py
выглядит следующим образом:
Командная строка Windows
C:\Users\john\Documents>python continue.py
4
3
1
0
Loop ended.
На этот раз, когда n
становится 2
, оператор continue
приводит к завершению этой итерации. Таким образом, 2
не выводится. Выполнение возвращается в начало цикла, условие переоценивается, и оно по-прежнему истинно. Цикл возобновляется и завершается, когда n
становится 0
, как и раньше.
Оператор else
Python допускает необязательное предложение else
в конце цикла while
. Это уникальная особенность Python, которой нет в большинстве других языков программирования. Синтаксис показан ниже:
while <expr>:
<statement(s)>
else:
<additional_statement(s)>
Указанный в пункте else
<additional_statement(s)>
будет выполнен, когда цикл while
завершится.
Сейчас вы, возможно, подумаете: "Как это может быть полезно?". Вы можете сделать то же самое, поместив эти утверждения сразу после цикла while
, без else
:
while <expr>:
<statement(s)>
<additional_statement(s)>
В чем разница?
В последнем случае, без условия else
, <additional_statement(s)>
будет выполнен после завершения цикла while
, независимо ни от чего.
Когда <additional_statement(s)>
помещается в предложение else
, он будет выполнен только в том случае, если цикл завершится "по исчерпанию", то есть если цикл будет итерироваться до тех пор, пока управляющее условие не станет ложным. Если цикл завершается оператором break
, то предложение else
не будет выполнено.
Рассмотрим следующий пример:
>>> n = 5
>>> while n > 0:
... n -= 1
... print(n)
... else:
... print('Loop done.')
...
4
3
2
1
0
Loop done.
В этом случае цикл повторялся до тех пор, пока условие не было исчерпано: n
стало 0
, поэтому n > 0
стало ложным. Поскольку цикл, так сказать, прожил свою естественную жизнь, был выполнен пункт else
. Теперь обратите внимание на разницу здесь:
>>> n = 5
>>> while n > 0:
... n -= 1
... print(n)
... if n == 2:
... break
... else:
... print('Loop done.')
...
4
3
2
Этот цикл преждевременно завершается с помощью break
, поэтому предложение else
не выполняется.
Может показаться, что значение слова else
не совсем подходит для цикла while
, как и для оператора if
.
Одна из следующих интерпретаций может помочь сделать это более интуитивно понятным:
-
Представьте себе заголовок цикла (
while n > 0
) какif
оператор (if n > 0
), который выполняется снова и снова, а пунктelse
выполняется, когда условие становится ложным. -
Думайте о
else
так, как если бы это былоnobreak
, в том смысле, что блок, который следует за ним, будет выполнен, если не былоbreak
.
Если вы не находите ни одну из этих интерпретаций полезной, то смело игнорируйте их.
Когда может быть полезным предложение else
в цикле while
? Одна из распространенных ситуаций - поиск определенного элемента в списке. Вы можете использовать break
для выхода из цикла, если элемент найден, а предложение else
может содержать код, который будет выполнен, если элемент не будет найден:
>>> a = ['foo', 'bar', 'baz', 'qux']
>>> s = 'corge'
>>> i = 0
>>> while i < len(a):
... if a[i] == s:
... # Processing for item found
... break
... i += 1
... else:
... # Processing for item not found
... print(s, 'not found in list.')
...
corge not found in list.
Примечание: Код, показанный выше, полезен для иллюстрации концепции, но на самом деле вы вряд ли будете искать список таким образом.
Прежде всего, списки обычно обрабатываются с помощью определенной итерации, а не цикла while
. Определенная итерация рассматривается в следующем уроке этой серии.
Во-вторых, Python предоставляет встроенные способы поиска элемента в списке. Вы можете использовать оператор in
:
>>> if s in a:
... print(s, 'found in list.')
... else:
... print(s, 'not found in list.')
...
corge not found in list.
Также подойдет метод list.index()
. Этот метод вызывает исключение ValueError
, если элемент не найден в списке, поэтому для его использования необходимо понимать обработку исключений. В Python для обработки исключения используется оператор try
. Пример приведен ниже:
>>> try:
... print(a.index('corge'))
... except ValueError:
... print(s, 'not found in list.')
...
corge not found in list.
Вы узнаете об обработке исключений позже в этой серии.
Клаузула else
с циклом while
- это немного странное явление, которое не часто встречается. Но не отказывайтесь от него, если вы найдете ситуацию, в которой, по вашему мнению, он добавит ясности вашему коду!
Бесконечные циклы
Предположим, что вы написали цикл while
, который теоретически никогда не заканчивается. Звучит странно, правда?
Рассмотрим этот пример:
>>> while True:
... print('foo')
...
foo
foo
foo
.
.
.
foo
foo
foo
Traceback (most recent call last):
File "<pyshell#2>", line 2, in <module>
print('foo')
KeyboardInterrupt
This code was terminated by Ctrl+C, which generates an interrupt from the keyboard. В противном случае он продолжался бы бесконечно. Многие строки вывода foo
были удалены и заменены вертикальным многоточием в показанном выводе.
Очевидно, что никогда True
не будет ложным, иначе у всех нас будут большие проблемы. Таким образом, while True:
инициирует бесконечный цикл, который теоретически будет выполняться вечно.
Возможно, это не похоже на то, что вы хотели бы сделать, но такая схема на самом деле довольно распространена. Например, вы можете написать код для службы, которая запускается и работает вечно, принимая запросы на обслуживание. "Вечно" в данном контексте означает, пока вы его не выключите или пока не наступит тепловая смерть Вселенной, в зависимости от того, что наступит раньше.
Более прозаично, помните, что из циклов можно выйти с помощью оператора break
. Возможно, будет проще завершить цикл, основываясь на условиях, распознанных в теле цикла, а не на условии, оцененном в верхней части.
Вот еще один вариант цикла, показанного выше, который последовательно удаляет элементы из списка с помощью .pop()
, пока он не станет пустым:
>>> a = ['foo', 'bar', 'baz']
>>> while True:
... if not a:
... break
... print(a.pop(-1))
...
baz
bar
foo
Когда a
становится пустым, not a
становится истиной, и оператор break
выходит из цикла.
Вы также можете указать несколько операторов break
в цикле:
while True:
if <expr1>: # One condition for loop termination
break
...
if <expr2>: # Another termination condition
break
...
if <expr3>: # Yet another
break
В подобных случаях, когда существует несколько причин для завершения цикла, часто бывает удобнее break
выходить из нескольких разных мест, а не пытаться указать все условия завершения в заголовке цикла.
Бесконечные циклы могут быть очень полезны. Только помните, что в какой-то момент цикл должен быть разорван, чтобы он не стал бесконечным.
Вложенные while
циклы
В общем случае управляющие структуры Python могут быть вложены друг в друга. Например, условные операторы if
/elif
/else
могут быть вложены друг в друга:
if age < 18:
if gender == 'M':
print('son')
else:
print('daughter')
elif age >= 18 and age < 65:
if gender == 'M':
print('father')
else:
print('mother')
else:
if gender == 'M':
print('grandfather')
else:
print('grandmother')
Аналогично, цикл while
может быть заключен внутри другого цикла while
, как показано здесь:
>>> a = ['foo', 'bar']
>>> while len(a):
... print(a.pop(0))
... b = ['baz', 'qux']
... while len(b):
... print('>', b.pop(0))
...
foo
> baz
> qux
bar
> baz
> qux
Утверждение break
или continue
, встречающееся во вложенных циклах, применяется к ближайшему вложенному циклу:
while <expr1>:
statement
statement
while <expr2>:
statement
statement
break # Applies to while <expr2>: loop
break # Applies to while <expr1>: loop
Кроме того, циклы while
могут быть вложены внутрь операторов if
/elif
/else
, и наоборот:
if <expr>:
statement
while <expr>:
statement
statement
else:
while <expr>:
statement
statement
statement
while <expr>:
if <expr>:
statement
elif <expr>:
statement
else:
statement
if <expr>:
statement
На самом деле, все управляющие структуры Python можно смешивать друг с другом в любой степени, которая вам необходима. Так и должно быть. Представьте, как было бы неприятно, если бы существовали неожиданные ограничения вроде "Цикл while
не может содержаться внутри оператора if
" или "Циклы while
могут быть вложены друг в друга не более чем на четыре глубины". Вам будет очень трудно запомнить их все.
Кажущиеся произвольными числовые или логические ограничения считаются признаком плохого дизайна программного языка. К счастью, в Python вы их не найдете.
Однострочные while
циклы
Как и в случае с оператором if
, цикл while
может быть задан в одной строке. Если в блоке, составляющем тело цикла, содержится несколько операторов, их можно разделить точками с запятой (;
):
>>> n = 5
>>> while n > 0: n -= 1; print(n)
4
3
2
1
0
Однако это работает только с простыми утверждениями. Вы не можете объединить два составных оператора в одной строке. Таким образом, вы можете указать цикл while
в одной строке, как указано выше, и написать оператор if
в одной строке:
>>> if True: print('foo')
foo
Но вы не можете сделать этого:
>>> while n > 0: n -= 1; if True: print('foo')
SyntaxError: invalid syntax
Помните, что PEP 8 не рекомендует использовать несколько утверждений в одной строке. Поэтому вам, вероятно, не стоит делать все это очень часто.
Заключение
В этом уроке вы узнали о бесконечной итерации с помощью цикла Python while
. Теперь вы можете:
- Построение основных и сложных циклов
while
- Прерывайте выполнение циклов с помощью
break
иcontinue
- Используйте предложение
else
с цикломwhile
- Работайте с бесконечными циклами
Теперь у вас должно быть хорошее представление о том, как выполнять кусок кода повторно.
В следующем уроке этой серии мы рассмотрим бесконечную итерацию с for
циклами - повторяющееся выполнение, в котором количество повторений задается явно.