Содержание
Из предыдущих материалов данной серии статей, у вас уже есть необходимое количество кодов Python. Все, что вы видели ранее, состояло из последовательного выполнения, в которых выражения всегда выполняются точно друг за другом в указанном порядке.
Но мир зачастую гораздо сложнее. Часто программе приходится пропускать некоторые выражения, выполнять серию повторно или выбирать между альтернативными наборами наилучший для выполнения.
Вот тут-то и появляются операторы управления. Операторы управления занимаются порядком выполнения выражений в программе (называемой потоком управления программы).
Вот что вы узнаете из этого урока: вы столкнетесь со своим первым оператором управления Python, оператором if
.
В реальном мире мы обычно даем оценку информации вокруг нас, а затем выбираем тот или иной порядок действий на основе того, что мы наблюдаем:
Если будет хорошая погода, я подстригу газон. (Подразумевается, что если погода не будет хорошей, то я не буду косить газон.)
В программе на Python оператор if
— это способ принятия такого рода решений. Он допускает условное выполнение оператора или группы операторов на основе значения выражения.
В общих чертах этот урок выглядит следующим образом:
- Во-первых, вы получите краткий обзор оператора if в его простейшей форме.
- Далее, используя оператор
if
в качестве модели, вы увидите, почему операторы управления требуют некоторые механизмы для группировки отступов или блоков вместе. Вы узнаете, как это делается в Python. - Наконец, вы свяжете все это вместе и научитесь писать сложный код принятия решений.
Готовы? Поехали!
Знакомство с оператором If
Мы начнем с самого основного типа выражения if
. Его простейшая форма:
<statement>
if <expr>: <statement>
В форме, показанной выше:
<expr>
— это оператор, вычисляемый в логическом контексте.<statement>
— это допустимый оператор Python,который должен иметь отступ. (Скоро вы поймете почему)Если имеет значение true (вычисляется до значения "truthy"), то выполняется . Если имеет значение false, то пропускается и не выполняется.
Обратите внимание, что двоеточие (:) после обязательно. Некоторые языки программирования требуют, чтобы был заключен в круглые скобки, но в Python это не нужно.
Вот несколько примеров оператора if
:
y = 5
if x < y: # Правда
print('yes')
if y < x: # Ложь
print('yes')
if x: # Ложь
print('yes')
if y: # Правда
print('yes')
if x or y: # Правда
print('yes')
if x and y: # Ложь
print('yes')
if 'aul' in 'grault': # Правда
print('yes')
if 'quux' in ['foo', 'bar', 'baz']: # Ложь
print('yes')
x = 0 y = 5 if x < y: # Правда print('yes') if y < x: # Ложь print('yes') if x: # Ложь print('yes') if y: # Правда print('yes') if x or y: # Правда print('yes') if x and y: # Ложь print('yes') if 'aul' in 'grault': # Правда print('yes') if 'quux' in ['foo', 'bar', 'baz']: # Ложь print('yes')
Примечание: Если вы пробуете эти примеры в интерактивном режиме в сеансе REPLએ, вы обнаружите, что при нажатии клавиши Enter после ввода оператора print('yes')
ничего не произойдет.
Поскольку это многострочный оператор, вам нужно нажать Enter во второй раз, чтобы сообщить интерпретатору, что вы закончили с ним. Эта дополнительная новая строка не нужна в коде, выполняемом из файла скрипта.
Группировка операторов: отступы и блоки
Пока все идет хорошо.
Но предположим, что вы хотите вычислить условие, а затем сделать больше действий, если это правда:
Если погода будет хорошая, то я буду:
Косить лужайку Полоть огород Гулять с собакой (Если погода не будет хорошей, то я не буду делать ничего из этого)
Во всех приведенных выше примерах за каждым if
<expr>
: следует только один оператор <statement>
. Должен быть какой-то способ сказать: "если <expr>
истина, то сделайте все следующие вещи"
Обычный подход, используемый большинством языков программирования, заключается в определении синтаксического устройства, которое группирует несколько операторов в один составной оператор или блок. Блок рассматривается синтаксически как единое целое. Если он является целью оператора if
и <expr>
имеет значение истина, то выполняются все операторы в блоке. Если <expr>
является ложным, то ни один из них не является ложным.
Практически все языки программирования предоставляют возможность определять блоки, но не все они обеспечивают это одинаково. Давайте посмотрим, как это делает Python.
Python: все дело в отступе
Python следует условности, известной как правило off-side, термин, придуманный британским ученым-компьютерщиком Питером Дж. Языки, которые придерживаются правила off-side, определяют блоки отступом. Python — один из небольшого набора автономных языков.
Напомним из предыдущего урока по структуре программы Python, что отступ имеет особое значение в программе Python. Теперь вы знаете почему: отступ используется для определения составных операторов или блоков. В программе Python непрерывные операторы, которые имеют отступы до одного и того же уровня, считаются частью одного и того же блока.
Таким образом, составной оператор if
в Python выглядит следующим образом:
<statement>
<statement>
...
<statement>
<following_statement>
if <expr>: <statement> <statement> ... <statement> <following_statement>
Здесь все операторы на соответствующем уровне отступа (строки 2‑5) считаются частью одного блока. Весь блок выполняется, если <expr> имеет значение true, или пропускаются, если <expr> имеет значение false. В любом случае выполнение продолжается с <following_statement> (строка 6).
Обратите внимание, что нет маркера, обозначающего конец блока. Скорее, конец блока обозначается линией, отступ которой меньше, чем линии самого блока.
Примечание: в документации Python группа операторов, определяемая отступом, часто называется набором. В этой серии статей термины блок и набор взаимозаменяемы.
Рассмотрим этот скрипт foo.py:
print('Выражение истина')
print('Выполнение инструкции')
print('...')
print('Готово')
if 'foo' in ['bar', 'baz', 'qux']: print('Выражение истина') print('Выполнение инструкции') print('...') print('Готово')
После старта foo.py производит данный вывод:
After conditional
C:\Users\john\Documents>python foo.py After conditional
Четыре оператора print () в строках 2-5 имеют отступы на одном уровне. Они составляют блок, который был бы выполнен, если бы условие было истинным. Но это ложь, поэтому все утверждения в блоке пропускаются. После завершения сложного оператора if
(независимо от того, выполняются ли операторы в блоке в строках 2-5 или нет) выполнение переходит к первому оператору с меньшим уровнем отступа: оператору print() в строке 6.
Блоки могут быть вложены на произвольную глубину. Каждый отступ определяет новый блок, и каждый выход завершает предыдущий блок. Полученная структура проста, последовательна и интуитивно понятна.
Вот более сложный файл сценария под названием blocks.py:
# --- --
if 'foo' in ['foo', 'bar', 'baz']: # x
print('Условие имеет значение истина') # x
if 10 > 20: # x
print('Внутреннее состояние') # x
print('Между внутренними условиями') # x
if 10 < 20: # x
print('Внутренние состояние 2') # x
print('Окончание внешнего состояния') # x
print('Через внешнее состояние') # x
# Does line execute? Да Нет # --- -- if 'foo' in ['foo', 'bar', 'baz']: # x print('Условие имеет значение истина') # x if 10 > 20: # x print('Внутреннее состояние') # x print('Между внутренними условиями') # x if 10 < 20: # x print('Внутренние состояние 2') # x print('Окончание внешнего состояния') # x print('Через внешнее состояние') # x
Выходные данные, сгенерированные при запуске этого скрипта, показаны ниже:
Outer condition is true
Between inner conditions
Inner condition 2
End of outer condition
After outer condition
C:\Users\john\Documents>python blocks.py Outer condition is true Between inner conditions Inner condition 2 End of outer condition After outer condition
Примечание: Если вам интересно, то правило off-side является причиной необходимости дополнительной новой строки при вводе многострочных операторов в сеансе REPLએ. В противном случае интерпретатор не может знать, что последний оператор блока был введен.
Что делают другие языки?
Возможно, Вам интересно, какие существуют альтернативы. Как определяются блоки в языках, которые не придерживаются правила off-side?
Тактика, используемая большинством языков программирования, заключается в назначении специальных маркеров, которые отмечают начало и конец блока. Например, в Perlએ блоки определяются с помощью пар фигурных скобок ({}) следующим образом:
<statement>;
<statement>;
...
<statement>;
}
<following_statement>;
if (<expr>) { <statement>; <statement>; ... <statement>; } <following_statement>;
C/C++, Java и целый ряд других языков используют фигурные скобки таким образом.
Другие языки, такие как Algol и Pascal, используют ключевые слова begin и end для включения блоков.
Что лучше?
Лучшее — в глазах смотрящего. В целом программисты, как правило, довольно сильно переживают по поводу того, как они что-то делают. Споры о достоинствах правила офсайда могут разгораться довольно жарко.
Достоинства:
Недостатки:
Нравится вам это или нет, но если вы программируете на Python, вы застряли с правилом off-side. Все структуры управления в Python используют его.
Как бы то ни было, многие программисты, которые привыкли к языкам с более традиционными средствами определения блоков, изначально отошли от пути Python, но затем освоили и даже стали отдавать ему предпочтение.
Операторы else
и elif
Теперь вы знаете, как использовать оператор if
для условного выполнения одного оператора или блока из нескольких операторов. Пришло время выяснить, что еще вы можете сделать.
Иногда вы хотите оценить условие и выбрать один путь, если это истина и указать альтернативный путь, если это не так. Это делается с помощью предложения else
:
<statement(s)>
else:
<statement(s)>
if <expr>: <statement(s)> else: <statement(s)>
Если <expr>
имеет значение true, то выполняется первый набор, а второй пропускается. Если <expr>
имеет значение false, то первый набор пропускается, а второй выполняется. В любом случае, выполнение затем возобновляется после второго набора. Оба набора определяются отступом, как описано выше.
В этом примере x меньше 50, поэтому выполняется первый набор (строки 4-5), а второй набор (строки 7-8) пропускается:
if x < 50:
print('(первый набор)')
print('x is small')
else:
print('(второй набор)')
print('x is large')
x = 20 if x < 50: print('(первый набор)') print('x is small') else: print('(второй набор)') print('x is large')
Здесь, с другой стороны, x больше 50, поэтому первый набор передается, а второй выполняется:
if x < 50:
print('(первый набор)')
print('x is small')
else:
print('(второй набор)')
print('x is large')
x = 120 if x < 50: print('(первый набор)') print('x is small') else: print('(второй набор)') print('x is large')
Существует также синтаксис для выполнения ветвления, основанный на нескольких альтернативах. Для этого используйте одно или несколько предложений elif
(сокращение от else if). Python вычисляет каждый <expr>
по очереди и выполняет набор, соответствующий Первому, который является истинным. Если ни одно из выражений не является истиной и указано предложение else
, то выполняется этот набор:
<statement(s)>
elif <expr>:
<statement(s)>
elif <expr>:
<statement(s)>
...
else:
<statement(s)>
if <expr>: <statement(s)> elif <expr>: <statement(s)> elif <expr>: <statement(s)> ... else: <statement(s)>
Можно указать произвольное количество предложений elif
. Предложение else
является необязательным. Если есть, то он должен быть указан последним:
if name == 'Fred':
print('Hello Fred')
elif name == 'Xander':
print('Hello Xander')
elif name == 'Joe':
print('Hello Joe')
elif name == 'Arnold':
print('Hello Arnold')
else:
print("I don't know who you are!")
name = 'Joe' if name == 'Fred': print('Hello Fred') elif name == 'Xander': print('Hello Xander') elif name == 'Joe': print('Hello Joe') elif name == 'Arnold': print('Hello Arnold') else: print("I don't know who you are!")
По большей мере, будет выполнен один из указанных блоков кода. Если предложение else
не включено и все условия ложны, то ни один из блоков не будет выполнен.
Примечание: использование длинного ряда if/elif/else
может быть немного неудобным, особенно когда действия представляют собой простые операторы, такие как print()
.
Вот одна из возможных альтернатив приведенному выше примеру с использованием метода dict. get() :
'Fred': 'Hello Fred',
'Xander': 'Hello Xander',
'Joe': 'Hello Joe',
'Arnold': 'Hello Arnold'
}
print(names.get('Joe', "I don't know who you are!"))
print(names.get('Rick', "I don't know who you are!"))
names = { 'Fred': 'Hello Fred', 'Xander': 'Hello Xander', 'Joe': 'Hello Joe', 'Arnold': 'Hello Arnold' } print(names.get('Joe', "I don't know who you are!")) print(names.get('Rick', "I don't know who you are!"))
Вспомните из статьи про словари Python, что метод dict. get () ищет в словаре указанный ключ и возвращает соответствующее значение, если оно найдено, или заданное значение по умолчанию, если его нет.
Оператор if
с предложениями elif
использует оценку короткого замыкания, аналогичную тому, что вы видели с операторами and
и or
. Как только одно из выражений оказывается истинным и его блок выполняется, ни одно из оставшихся выражений не проверяется. Это показано ниже:
if 'a' in 'bar':
print('foo')
elif 1/0:
print("This won't happen")
elif var:
print("This won't either")
var # Not defined if 'a' in 'bar': print('foo') elif 1/0: print("This won't happen") elif var: print("This won't either")
Второе выражение содержит деление на ноль, а третье ссылается на неопределенную переменную var. Любой из них вызовет ошибку, но ни один из них не будет вычислен, поскольку первое указанное условие истинно.
Оператор If
в одну строку
Принято писать, если <expr>
и <statement>
с отступом на следующей строке, как это:
<statement>
if <expr>: <statement>
Но допустимо написать целое утверждение if
на одной строке. Будет выглядеть так:
if <expr>: <statement>
В одной строке может быть даже несколько <statement>
, разделенных точкой с запятой:
if <expr>: <statement_1>; <statement_2>; ...; <statement_n>
Но что это значит? Есть два объяснения:
1) Если <expr>
имеет значение true, выполняется <statement_1>
.
Затем выполните команду <statement_2>
... <statement_n>
безусловно, независимо от того, является ли <expr>
истинным или нет.
2) Если <expr>
имеет значение true, выполните все действия <statement_1>
... <statement_n>
. В противном случае не выполняйте ни одного из них.
Python принимает последнее объяснение. Точка с запятой, разделяющая <expr>
, имеет более высокий приоритет, чем двоеточие, следующее за <expr>
— на компьютерном сленге точка с запятой, как говорят, связывается более плотно, чем двоеточие. Таким образом, <statement>
рассматриваются как набор, либо все они выполняются, либо ни один из них не выполняется:
if 'z' in 'foo': print('1'); print('2'); print('3')
if 'f' in 'foo': print('1'); print('2'); print('3') if 'z' in 'foo': print('1'); print('2'); print('3')
Несколько операторов могут быть указаны в той же строке, что и предложение elif
или else
:
if x == 1: print('foo'); print('bar'); print('baz')
elif x == 2: print('qux'); print('quux')
else: print('corge'); print('grault')
x = 3
if x == 1: print('foo'); print('bar'); print('baz')
elif x == 2: print('qux'); print('quux')
else: print('corge'); print('grault')
x = 2 if x == 1: print('foo'); print('bar'); print('baz') elif x == 2: print('qux'); print('quux') else: print('corge'); print('grault') x = 3 if x == 1: print('foo'); print('bar'); print('baz') elif x == 2: print('qux'); print('quux') else: print('corge'); print('grault')
Хотя все это работает, и интерпретатор допускает это, но обычно это не рекомендуется, потому что это приводит к плохой читабельности, особенно для сложных операторов if
. PEP 8એ (pep8 – это модуль, позволяющий проверять, соответствует ли код определенному стандарту)специально рекомендует этого не делать.
Как обычно, это дело вкуса. Большинство людей нашли бы следующее более привлекательным и более легким для понимания на первый взгляд, пример до этого:
if x == 1:
print('foo')
print('bar')
print('baz')
elif x == 2:
print('qux')
print('quux')
else:
print('corge')
print('grault')
x = 3 if x == 1: print('foo') print('bar') print('baz') elif x == 2: print('qux') print('quux') else: print('corge') print('grault')
Однако если оператор if достаточно прост, то размещение всего этого в одной строке может быть разумным.
.
.
.
if debugging: print('About to call function foo()')
foo()
debugging = True # Установите значение True, чтобы включить отладку. . . . if debugging: print('About to call function foo()') foo()
Условные операторы
Python поддерживает дополнительный метод принятия решений, называемую условным выражением. (Он также упоминается как условный оператор или тернарный оператор в различных местах документации Python).
В своей простейшей форме синтаксис условного выражения выглядит следующим образом:
<expr1> if <conditional_expr> else <expr2>
Это отличается от форм операторов if
, перечисленных выше, потому что это не управляющая структура направляет поток выполнения программы. Он действует скорее как оператор, определяющий выражение. В приведенном выше примере сначала вычисляется <conditional_expr>
. Если истина, то выражение вычисляется как <expr1>
. Если ложь, то выражение вычисляется как <expr2>
.
Обратите внимание на не очевидный порядок: сначала вычисляется среднее выражение, и на основе этого результата возвращается одно из выражений на концах. Вот несколько примеров, которые, надеюсь, помогут прояснить ситуацию:
print("Let's go to the", 'beach' if not raining else 'library')
raining = True
print("Let's go to the", 'beach' if not raining else 'library')
age = 12
s = 'minor' if age < 21 else 'adult'
s
'yes' if ('qux' in ['foo', 'bar', 'baz']) else 'no'
raining = False print("Let's go to the", 'beach' if not raining else 'library') raining = True print("Let's go to the", 'beach' if not raining else 'library') age = 12 s = 'minor' if age < 21 else 'adult' s 'yes' if ('qux' in ['foo', 'bar', 'baz']) else 'no'
Примечание: условное выражение Python аналогично синтаксису <conditional_expr>
? <expr1>
: <expr2>
, используемому многими другими языками-C, Perl и Java. На самом деле, оператор ?: обычно называют тернарным оператором в этих языках, что, вероятно, является причиной того, что условное выражение Python иногда называют тернарным оператором Python.
Вы можете видеть в PEP 308એ (PEP 308 — Условные выражения), что синтаксис <conditional_expr>
? <expr1>
: <expr2>
был рассмотрен для Python, но в конечном счете отвергнут в пользу синтаксиса, показанного выше.
Обычно условное выражение используется для выбора назначения переменной. Например, предположим, что вы хотите найти большее из двух чисел. Конечно, есть встроенная функция max (), которая делает именно это (и многое другое), что вы могли бы использовать. Но предположим, вы хотите написать свой собственный код с нуля.
Вы можете использовать стандартный оператор if
с предложением else
:
m = a
else:
m = b
if a > b: m = a else: m = b
Но условный оператор короче и, возможно, более читабельнее:
m = a if a > b else b
Не забывайте, что условное выражение ведет себя как синтаксическое выражение. Его можно использовать как часть более длинного выражения. Условное выражение имеет более низкий приоритет, чем практически все остальные операторы, поэтому для его группировки необходимы круглые скобки.
В следующем примере оператор + связывается более плотно, чем условное выражение, поэтому сначала вычисляются ++x и y+2y + 2, а затем условное выражение. Скобки во втором случае не нужны и результат не меняется:
z = 1 + x if x > y else y + 2
z
z = (1 + x) if x > y else (y + 2)
z
x = y = 40 z = 1 + x if x > y else y + 2 z z = (1 + x) if x > y else (y + 2) z
Если вы хотите, чтобы условное выражение было вычислено первым, вам нужно окружить его группирующими скобками. В следующем примере сначала вычисляется (x, если x > y, иначе y). В результате получается y, который равен 40, поэтому присваивается z 1+40+21 + 40 + 2 = 43:
z = 1 + (x if x > y else y) + 2
z
x = y = 40 z = 1 + (x if x > y else y) + 2 z
Если вы используете условное выражение как часть более крупного выражения, вероятно, будет хорошей идеей использовать группирующие скобки для уточнения, даже если они не нужны.
Условные выражения также используют оценку короткого замыкания, как и составные логические выражения. Части условного выражения не вычисляются, если в этом нет необходимости.
В выражении <expr1>
, если <conditional_expr>
иначе <expr2>
:
Вы можете проверить это, используя термины, которые вызвали бы ошибку:
1/0 if False else 'bar'
'foo' if True else 1/0 1/0 if False else 'bar'
В обоих случаях условия 1/0 не оцениваются, поэтому никаких исключений не возникнет.
Условные выражения также могут быть объединены вместе, как своего рода альтернативная структура if/elif/else
, как показано здесь:
'bar' if (x == 2) else
'baz' if (x == 3) else
'qux' if (x == 4) else
'quux'
)
s
s = ('foo' if (x == 1) else 'bar' if (x == 2) else 'baz' if (x == 3) else 'qux' if (x == 4) else 'quux' ) s
Неясно, имеет ли это какое-либо существенное преимущество перед соответствующим оператором if/elif/else
, но это синтаксически правильно для Python.
Оператор pass
в Python
Иногда вы можете обнаружить, что хотите написать то, что называется заглушкой кода: заполнитель для того места, где вы в конечном итоге поместите блок кода, который вы еще не реализовали.
В языках, где разделители токенов используются для определения блоков, таких как фигурные скобки в Perl и C, пустые разделители могут использоваться для определения заглушки кода. Например, ниже приведен рабочий код Perl или C:
if (x)
{
}
# This is not Python if (x) { }
Здесь пустые фигурные скобки определяют пустой блок. Perl или C оценят выражение x, а затем, даже если оно истина, ничего не произойдет.
Поскольку в Python используются отступы, а не разделители, то не возможно указать блок пустым. Если вы вводите оператор if
с if <expr>
:, то что-то должно идти сразу после него, либо в той же строке, либо с отступом в следующей строке.
Рассмотрим этот скрипт foo.py:
print('foo')
if True: print('foo')
После этого, вы получите:
File "foo.py", line 3
print('foo')
^
IndentationError: expected an indented block
C:\Users\john\Documents\Python\doc>python foo.py File "foo.py", line 3 print('foo') ^ IndentationError: expected an indented block
Оператор pass
решает эту проблему. Он совершенно не изменит поведение программы. Он используется в качестве заполнителя, чтобы сделать интерпретатора счастливым в любой ситуации, когда синтаксически требуется утверждение, но на самом деле вы ничего не хотите делать:
pass
print('foo')
if True: pass print('foo')
Сейчас foo.py работает без ошибок:
foo
C:\Users\john\Documents\Python\doc>python foo.py foo
Вывод
С завершением этого урока вы начинаете писать код Python, который выходит за рамки простого последовательного выполнения:
if
, который позволяет условно выполнить оператор или блок на основе оценки данных программы.Все эти концепции имеют решающее значение для разработки более сложного кода Python.
В следующих двух статьях будут представлены две новые структуры управления: оператор while
и оператор for
. Эти помощники облегчат повторение, многократное выполнение оператора или блока операторов.
Оригинал статьи: Conditional Statements in Python