Оператор выбора в Python (if else)
Фундаментальная важность условий для любого из языков программирования заключается в их возможности описывать большую часть логики работы программы.
if else — это оператор, управляющий условным ветвлением. Простыми словами это конструкция в Python, указывающая интерпретатору, следует ли выполнять определенный участок кода или нет.
Как и все прочие составные инструкции языка, оператор выбора также поддерживает свойство вложенности. Это означает, что использование if else
позволяет создавать внутри программного модуля так называемое логическое ветвление.
Как работает if else
Синтаксис
Оператор if else
в языке Python — это типичная условная конструкция, которую можно встретить и в большинстве других языков программирования.
# самый простой пример, где есть всего одно условие
a = 1
if a == 1:
print("It is true")
> It is true
Синтаксически конструкция выглядит следующим образом:
- сначала записывается часть
if
с условным выражением, которое возвращает истину или ложь; - затем может следовать одна или несколько необязательных частей
elif
(в других языках вы могли встречатьelse if
); - Завершается же запись этого составного оператора также необязательной частью
else
.
count = 1
# условное выражение может быть сколь угодно сложным,
# и может быть сколь угодно много elif-частей
if True and count == 1 and count == 2:
print("if")
elif count == 'count':
print("First elif")
elif count == 14.2:
print("Second elif")
elif count == 1:
print("Nth elif")
else:
print("Else")
> Nth elif
Для каждой из частей существует ассоциированный с ней блок инструкций, которые выполняются в случае истинности соответствующего им условного выражения.
b = 10
if b == 10:
# любое количество инструкций
print(b)
b = b * 15
b = b - 43
b = b ** 0.5
print(b)
elif b == 20:
print("You will not see me")
else:
print("And me")
> 10
> 10.344080432788601
То есть интерпретатор начинает последовательное выполнение программы, доходит до if
и вычисляет значение сопутствующего условного выражения. Если условие истинно, то выполняется связанный с if
набор инструкций. После этого управление передается следующему участку кода, а все последующие части elif
и часть else
(если они присутствуют) опускаются.
Отступы
Отступы — важная и показательная часть языка Python. Их смысл интуитивно понятен, а определить их можно, как размер или ширину пустого пространства слева от начала программного кода.
# начало кода
# код
# код
# код
# начало первого отступа
# первый отступ
# первый отступ
# начало второго отступа
# второй отступ
# второй отступ
# конец второго отступа
# конец первого отступа
Благодаря отступам, python-интерпретатор определяет границы блоков. Все последовательно записанные инструкции, чье смещение вправо одинаково, принадлежат к одному и тому же блоку кода. Конец блока совпадает либо с концом всего файла, либо соответствует такой инструкции, которая предшествует следующей строке кода с меньшим отступом.
var_a = 5
var_b = 10
var_c = 20
if var_c**2 > var_a * var_b:
# блок №1
if var_c < 100:
# блок №2
if var_c > 10:
# блок №3
var_a = var_a * var_b * var_c
# блок №2
var_b = var_a + var_c
# блок №1
var_c = var_a - var_b
print(var_a)
print(var_b)
print(var_c)
> 1000
> 1020
> -20
Таким образом, с помощью отступов появляется возможность создавать блоки на различной глубине вложенности, следуя простому принципу: чем глубже блок, тем шире отступ.
Примеры
Рассмотрим несколько практических примеров использования условного оператора.
Пример №1: создание ежедневного бэкапа (например базы данных):
from datetime import datetime
def daily_backup(last_backup_date):
"""
Передаем дату последнего бэкапа.
Если прошло больше 1 дня, создаем бэкап
"""
if not last_backup_date:
print(f"creating first backup [{datetime.now().date()}] ..")
return
delta = datetime.now() - last_backup_date
if delta.days > 0:
print(f"creating backup [{datetime.now().date()}] ..")
else:
print(f"backup on [{datetime.now().date()}] already exists")
daily_backup("")
> creating first backup [2020-08-15] ..
daily_backup(datetime(2020, 8, 14))
> creating backup [2020-08-15] ..
daily_backup(datetime(2020, 8, 15))
> backup on [2020-08-15] already exists
Пример №2: Проверка доступа пользователя к системе. В данном примере if
проверяет наличие элемента в списке:
BLACK_LIST = ['192.34.12.3', '192.34.12.5', '192.34.10.23']
USERS = ['rolli34', 'constantinpetrovv', 'kate901']
def access_available(user_name, ip):
if user_name in USERS:
if ip not in BLACK_LIST:
return True
else:
print(f"write to log: user {user_name} [ip: {ip}] in block list")
else:
print(f"write to log: user {user_name} [ip: {ip}] does not exists")
return False
if access_available("rolli34", "192.34.12.111"):
print(f"Hello!!")
> Hello!!
if access_available("rolli34", "192.34.10.23"):
print(f"Hello!!")
> write to log: user rolli34 [ip: 192.34.10.23] in block list
if access_available("devnull", "192.34.10.11"):
print(f"Hello!!")
> write to log: user devnull [ip: 192.34.10.11] does not exists
Пример №3: Валидация входных данных. В примере к нам приходят данные в формате json
. Нам необходимо выбрать все записи определенного формата:
NEED = {
"name": str,
"weight": int,
"age": int,
}
def is_valid(data):
valid = True
for need_key_name, need_type in NEED.items():
# проверяем наличие ключа
if need_key_name in data:
# если ключ есть, проверяем тип значения
data_type = type(data[need_key_name])
if data_type != need_type:
print(f"type error: '{need_key_name}' is {data_type}, need: {need_type}")
valid = False
else:
print(f"key error: '{need_key_name}' does not exists")
valid = False
return valid
if is_valid({"name": "Alex"}):
print("data is valid")
>
key error: 'weight' does not exists
key error: 'age' does not exists
if is_valid({"name": "Alex", "age": "18"}):
print("data is valid")
>
key error: 'weight' does not exists
type error: 'age' is <class 'str'>, need: <class 'int'>
if is_valid({"name": "Alex", "weight": 60, "age": 18}):
print("data is valid")
> data is valid
Оператор elif
elif
позволяет программе выбирать из нескольких вариантов. Это удобно, например, в том случае, если одну переменную необходимо многократно сравнить с разными величинами.
shinobi = 'Naruto'
if shinobi == 'Orochimaru':
print('fushi tensei')
elif shinobi == 'Naruto':
print('RASENGAN')
elif shinobi == 'Sasuke':
print('chidori')
> RASENGAN
Такая конструкция может содержать сколь угодно большую последовательность условий, которые интерпретатор будет по порядку проверять.
Но помните, что первое условие всегда задается с if
Также не стоит забывать, что как только очередное условие в операторе оказывается истинным, программа выполняет соответствующий блок инструкций, а после переходит к следующему выражению.
Из этого вытекает, что даже если несколько условий истинны, то исполнению подлежит все равно максимум один, первый по порядку, блок кода с истинным условием.
Если ни одно из условий для частей if
и elif
не выполняется, то срабатывает заключительный блок под оператором еlse
(если он существует).
Заглушка pass
Оператор-заглушка pass
заменяет собой отсутствие какой-либо операции.
Он может быть весьма полезен в случае, когда в ветвлении встречается много elif
-частей, и для определенных условий не требуется выполнять никакой обработки.
Наличие тела инструкции в Python обязательно
sum = 100000
account_first = 12000
account_second = 360000
if account_first > sum:
pass
elif account_second > sum:
pass
else:
print(sum)
if else в одну строку
Во многих языках программирования условие может быть записано в одну строку. Например, в JavaScript используется тернарный оператор:
# так выглядит условие в одну строку в JavaScript
const accessAllowed = (age > 21) ? true : false;
Читается это выражение так: если age
больше 21
, accessAllowed
равен true
, иначе — accessAllowed
равен false
.
В Python отсутствует тернарный оператор
Вместо тернарного оператора, в Питоне используют инструкцию if else
, записанную в виде выражения (в одно строку):
<expression if True> if <predicate> else <expression if False>
Пример:
number = -10
abs_number = number if number >= 0 else -number
print(abs_number)
Такая конструкция может показаться сложной, поэтому для простоты восприятия, нужно поделить ее на 3 блока:
Стоит ли использовать такой синтаксис? Если пример простой, то однозначно да:
# полная версия
count = 3
if count < 100:
my_number = count
else:
my_number = 100
# сокращенная версия
count = 3
my_number = count if count < 100 else 100
Вполне читаемо смотрятся и следующие 2 примера:
x = "Kate" if "Alex" in "My name is Alex" else "Mary"
print(x)
> Kate
y = 43 if 42 in range(100) else 21
print(y)
> 43
Но если вы используете несколько условий, сокращенная конструкция усложняется и становится менее читаемой:
x = 10
result = 100 if x > 42 else 42 if x == 42 else 0
print(result)
> 0
Вложенные условия
Ограничений для уровней вложенности в Python не предусмотрено, а регулируются они все теми же отступами:
# делать код менее читаемым можно до бесконечности
def run(action):
if action:
print(some_func())
else:
if some_func():
num = one_func()
if num:
if 0 < num < 100:
print(num)
else:
print('-')
Стоит ли использовать такие вложенности? Скорее нет, чем да. Одно из положений Python Zen гласит:
Flat is better than nested (развернутое лучше вложенного).
Большая вложенность имеет следующие недостатки:
- становится трудно легко найти, где заканчивается конкретный блок;
- код становится менее читаемым и сложным для понимания;
- возможно придется прокручивать окно редактора по горизонтали.
Но что делать, если в скрипте не получается уйти от большой вложенности if-else? 🤷♂️
Чтобы уйти от большой вложенности, попробуйте не использовать оператор else
Пример выше, можно записать следующим образом:
def run(action):
if action:
print(some_func())
return
if not some_func():
return
num = one_func()
if not num:
return
if 0 < num < 100:
print(num)
return
print('-')
Конструкция switch case
В Python отсутствует инструкция switch case
В языках, где такая инструкция есть, она позволяет заменить собой несколько условий if
и более наглядно выразить сравнение с несколькими вариантами.
# пример на C++
int main() {
int n = 5;
# сравниваем значение n поочередно со значениями case-ов
switch (n) {
case 1:
cout << n;
break;
case 2:
cout << n;
break;
# так как 5 не равняется ни 1-у, ни 2-м, то выполняется блок default
default:
cout << "There is not your number";
break;
}
return 0;
}
> There is not your number
Свято место пусто не бывает, поэтому в питоне такое множественное ветвление, в обычном случае, выглядит как последовательность проверок if-elif
:
n = 5
if n == 1:
print(n)
elif n == 2:
print(n)
else:
print("There is not your number")
> "There is not your number"
Однако есть и более экзотический вариант реализации этой конструкции, задействующий в основе своей python-словари:
switch_dict = {
1: 1,
2: 2,
3: 3,
}
print(switch_dict.get(5, "There is not your number"))
> "There is not your number"
Использование словарей позволяет, в качестве значений, хранить вызовы функций, тем самым, делая эту конструкцию весьма и весьма мощной и гибкой.
math case от Python 3.10 аналог switch/case
number = 1 switch_dict = { 1: 1, 2: 2, 3: 3, } print(switch_dict.get(number, "There is no your number")) > 1
Спасибо, поправили 😉
Спасибо!
Не понимаю, зачем в учебнике по Python указывать языковые конструкции из других языков. Это мешает пониманию основного материала.
В Python ниже версии 3.10 не было конструкции "switch case". Пример на С++ это просто наглядное представление, как выглядит такая конструкция.