Управляющие структуры

В языке Python условное ветвление реализуется с помощью инструкции if, а циклическая обработка – с помощью инструкций while и for ... in. В языке Python имеется также такая конструкция, как условное выражение – вариант инструкции if, аналог трехместного оператора (?:), имеющегося в C-подобных языках.

Условное ветвление

Общий синтаксис инструкции условного ветвления в языке Python имеет следующий вид:

if boolean_expression1:
    suite1
elif boolean_expression2:
    suite2
...
elif boolean_expressionN:
    suiteN
else:
    else_suite

Инструкция может содержать ноль или более предложений elif. Заключительное предложение else также является необязательным. Если необходимо предусмотреть ветку для какого-то особого случая, который не требует никакой обработки, в качестве блока кода этой ветки можно использовать инструкцию pass (она ничего не делает и просто является инструкцией-заполнителем, используемой там, где должна находиться хотя бы одна инструкция).

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

expression1 if boolean_expression else expression2

Если логическое выражение boolean_expression возвращает значение True, результатом всего условного выражения будет результат выражения expression1, в противном случае – результат выражения expression2.

Об использовании скобок

Предположим, что нам необходимо записать в переменную width значение 100 и прибавить к нему 10, если переменная margin имеет значение True. Мы могли бы написать такое выражение:

width = 100 + 10 if margin else 0	# ОШИБКА!

Особенно неприятно, что эта строка программного кода работает правильно, когда переменная margin имеет значение True, записывая значение 110 в переменную width. Но когда переменная margin имеет значение False, в переменную width вместо 100 будет записано значение 0. Это происходит потому, что интерпретатор Python воспринимает выражение 100 + 10 как часть expression1 условного выражения. Решить эту проблему можно с помощью круглых скобок:

width = 100 + (10 if margin else 0)

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

Условные выражения могут использоваться для видоизменения сообщений, выводимых для пользователя. Например, при выводе числа обработанных файлов, вместо того чтобы печатать «0 файл(ов)», «1 файл(ов)» или что-то подобное, можно было бы использовать пару условных выражений:

print("{0} файл{1}".format((count if count != 0 else "нет"), ("ов" if count % 10 not in [1, 2, 3, 4] else ("a" if count % 10 != 1 else ""))))

Циклы

В языке Python есть две инструкции циклов – while и for ... in.

Циклы while

Ниже приводится полный синтаксис цикла while:

while boolean_expression:
    while_suite
else:
    else_suite

Предложение else является необязательным. До тех пор, пока выражение boolean_expression возвращает значение True, в цикле будет выполняться блок while_suite. Если выражение boolean_expression вернет значение False, цикл завершится, и при наличии предложения else будет выполнен блок else_suite. Если внутри блока while_suite выполняется инструкция continue, то управление немедленно передается в начало цикла и выражение boolean_expression вычисляется снова. Если цикл не завершается нормально, блок предложения else не выполняется.

Необязательное предложение else имеет несколько сбивающее с толку название, поскольку оно выполняется во всех в случаях, когда цикл нормально завершается. Если цикл завершается в результате выполнения инструкции break или return, когда цикл находится внутри функции или метода, или в результате исключения, то блок else_suite предложения else не выполняется. (При возникновении исключительной ситуации интерпретатор Python пропускает предложение else и пытается отыскать подходящий обработчик исключения, о чем будет рассказываться в следующем разделе.) Плюсом такой реализации является одинаковое поведение предложения else в циклах while, в циклах for ... in и в блоках try ... except.

Рассмотрим пример, демонстрирующий предложение else в действии. Методы str.index() и list.index() возвращают индекс заданной подстроки или элемента или возбуждают исключение ValueError, если подстрока или элемент не найдены. Метод str.find() делает то же самое, но в случае неудачи он не возбуждает исключение, а возвращает значение -1. Для списков не существует эквивалентного метода, но при желании мы могли бы создать такую функцию, использующую цикл while:

def list_find(lst, target):
    index = 0
    while index < len(lst):
        if lst[index] == target:
            break
        index += 1
    else:
        index = -1
    return index

Эта функция просматривает список в поисках заданного элемента target. Если искомый элемент будет найден, инструкция break завершит цикл и вызывающей программе будет возвращен соответствующий индекс. Если искомый элемент не будет найден, цикл достигнет конца списка и завершится обычным способом. В случае нормального завер- шения цикла будет выполнен блок в предложении else, индекс получит значение -1 и будет возвращен вызывающей программе.

Циклы for

Подобно циклу while, полный синтаксис цикла for ... in также включает необязательное предложение else:

for expression in iterable:
    for_suite
else:
    else_suite

В качестве выражения expression обычно используется либо единственная переменная, либо последовательность переменных, как правило, в форме кортежа. Если в качестве выражения expression используется кортеж или список, каждый элемент итерируемого объекта iterable распаковывается в элементы expression.

Если внутри блока for_suite встретится инструкция continue, управление будет немедленно передано в начало цикла и будет начата новая итерация. Если цикл завершается по выполнении всех итераций и в цикле присутствует предложение else, выполняется блок else_suite. Если выполнение цикла прерывается принудительно (инструкцией break или return), управление немедленно передается первой инструкции, следующей за циклом, а дополнительное предложение else при этом пропускается. Точно так же, когда возбуждается исключение, интерпретатор Python пропускает предложение else и пытается отыскать подходящий обработчик исключения (о чем будет рассказываться в следующем разделе).

Ниже приводится версия функции list_find(), реализованная на базе цикла for ... in, которая так же, как и версия на базе цикла while, демонстрирует предложение else в действии:

def list_find(lst, target):
    for index, x in enumerate(lst):
        if x == target:
	    break
	else:
            index = -1
    return index

Как видно из этого фрагмента, переменные, созданные в выражении expression цикла for ... in, продолжают существовать после завершения цикла. Как и любые локальные переменные, они прекращают свое существование после выхода из области видимости, включающей их.