Оформление сложных условий
Условный оператор в обычной своей форме источником проблем является сравнительно редко. Однако само условие порой оказывается достаточно сложным и встает на пути к мечте любого разработчика. Речь, конечно же, о красивом и читаемом коде.
Возможно, я не там искал, но ни разу в стандартах оформления кода не встречал упоминаний о том, как быть со сложными условиями. Разобраться с ними — и есть цель данной статьи.
Так как с высасыванием из пальца у меня проблемы, в качестве источника примеров взята часть исходников GCC 4.8.2, для авторов которых стандарты оформления — не пустой звук. Используя примеры, буду приводить файл и строку начала, чтобы желающие могли убедиться, что все честно. Сразу замечу, что, так как примеры реальные и брались из ограниченного источника, некоторые из них могут оказаться не самыми удачными.
В контексте данной статьи сложным будем считать условие, которое состоит из нескольких подусловий и не удовлетворяет требованиям при записи в одну строку. Подразумеваются требования, например, к длине строки или читаемости.
Читаемость, как обычно, определяется на глаз, ибо в одних случаях 3-4 подусловия выделяются при первом же взгляде на участок кода, а в других и с двумя черт ногу сломит. Так, например, использование функций, приведения типов, побитовых операций или вложенности значительно усложняет чтение условий.
Следующий пример находится где-то на грани.
libgcc/fp-bit.c — 205:
if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
Но порой даже простое условие заставляет на мгновение задуматься.
libgcc/fp-bit.c — 1579:
if ((in.fraction.ll & (((USItype) 1
Естественно, если подобное будет частью условия, то его (результирующее условие) простым назвать трудно.
Примеры с директивами препроцессора внутри условий я намеренно не брал, так как это уже об еще более сложных условиях, выходящих за рамки статьи.
Для улучшения читаемости потребуется разбить условие на блоки. Так же придется поступить, если длина строки с условием превышает допустимую (часто оговаривается в стандартах). Принципы этого разбиения нас и интересуют по двум основным причинам. Во-первых, делать это надо так, чтобы не усугубить ситуацию. Во-вторых, нужно прийти к пусть негласному, но стандарту, ведь сам факт единообразия уже является плюсом к читаемости.
Первое, что приходит на ум, — использование вложенных условных операторов.
libgcc/fixed-bit.c — 84:
if ((((x ^ y) >> I_F_BITS) & 1) == 0) < if (((z ^ x) >> I_F_BITS) & 1) < . >>
libgcc/fp-bit.c — 361:
if (exp < EXPMAX) if (low >unity || (low == unity && (high & 1) == 1))
Если в первом случае не все так плохо, то во втором вложенное условие близко к тому, что и его необходимо будет дробить. А между тем растет вложенность кода. К тому же в случае с дизъюнкцией такой фокус не пройдет.
Более интересным вариантом являются многострочные условия. Такое решение для некоторых кажется неожиданным, хотя оно много где поддерживается (в тех же C, PHP, Python).
Идея разбиения заключается в том, что на каждой строке оставляется только одно подусловие.
libgcc/libgcc2.c — 1980
if (!recalc && (isinf (ac) || isinf (bd) || isinf (ad) || isinf (bc)))
Это условие читаемое и легко понимаемое. Но оно не соответствует ранее упомянутому правилу. Здесь всплывает польза однообразия. Если необходимость писать по одному подусловию в строку не оговорена, то анализ этого условия при чтении его усложняется. В обратном случае, даже встретив что-нибудь вроде libgcc/fp-bit.c — 1579 в качестве подусловия, заранее известно, что оно не является сложным.
Большинство многострочных условий в рассматриваемых исходниках все же соответствуют этой идее. Но не ограничиваться же только ею. Отступы в последнем примере подсказывают, что наглядно можно представить и вложенность условий при таком подходе. Единственное, что вызвало сомнение — все подобные условия были слишком уж однообразны, представляли из себя именно такую «лесенку», из-за чего появилась даже мысль о том, что это просто совпадение.
К счастью, нашелся целый один пример, который, без сомнения, подходит под мое определение красивого и понятного сложного условия.
libgcc/libgcov-driver.c — 688:
if (!all_prg->checksum && (cs_all->num != cs_prg->num || cs_all->runs != cs_prg->runs || cs_all->sum_all != cs_prg->sum_all || cs_all->run_max != cs_prg->run_max || cs_all->sum_max != cs_prg->sum_max))
Здесь и соблюден принцип одного подусловия на строку, и наглядно показана вложенность. Разбор такого условия прост, и этим приятен. Представьте его однострочным или в виде трех-четырех вложенных if'ов.
Естественно, совмещать подобное с вложенным условным оператором (как это сделано в libgcc/libgcc2.c — 1611 (примера в статье нет)) не стоит.
Мне на ум приходит еще один вариант реализации данного подхода, но он более громоздкий, и на практике я его не встречал. Что-то вроде следующего:
if ( condition1 && ( condition2 || condition3 ) )
Это лишь один из вариантов. Идея заключается в вынесении закрывающих скобок на отдельную строку. Это избавляет от «скачущих» отступов, как, например, в следующем примере.
libgcc/fixed-bit.c — 1013:
if ((BIG_SINT_C_TYPE) high > (BIG_SINT_C_TYPE) max_high || ((BIG_SINT_C_TYPE) high == (BIG_SINT_C_TYPE) max_high && (BIG_UINT_C_TYPE) low > (BIG_UINT_C_TYPE) max_low)) low = max_low; /* Maximum. */
Ну а расстановка скобок аналогична расстановке всем привычных операторных скобок и потому очевидна и понятна. Скобки для выделения вложенных условий, конечно же, обязательны, так как позволяют избежать ошибок, связанных с приоритетом логических операций.
Думаю, выводы не нужны, каждый для себя сделает сам. Ну а если данный вопрос все же затрагивался в каких-то стандартах или литературе, то ссылки, названия, авторы не помешают (цитаты приветствуются).
UPD: еще один хороший вариант — выделение частей сложного условия в отдельные булевы переменные. Не попалось подходящего рабочего примера, потому не упомянул изначально. За показательный код спасибо lexasss.
bool mustRdraw = (frame.isChanged() || target.isChanged()) || experiment.isRunning(); bool isFullScreen = frame.getSize().equal(screen.getSize()); if (isFullScreen && mustRedraw) < // redraw >
При правильных группировке условий и именовании переменных такой подход несет еще и документирующую функцию.
- условные конструкции
- оформление кода
- gcc
- Программирование
- Совершенный код
Условные операторы
Программа может выполняться постепенно: строка за строкой, выражение за выражением от начала и до конца, не пропуская ни единой строки кода. Но такое в реальности происходит редко. Зачастую необходимо ввести вариативность, чтобы при выполнении определенного условия, происходило одно, а при его невыполнении – другое. Так применяются условные операторы.
Определение
Условные операторы в Python 3 иногда называют операторами ветвления. Они созданы, чтобы программа могла выбрать, какой инструкции стоит следовать при определенном значении заданной переменной. Условные операторы состоят из заголовка и тела. Заголовок – это сама конструкция и то, что стоит рядом с ним (не в фигурных скобках в других языках программирования или перед двоеточием в Python). Тело – то, что написано после двоеточия. Чтобы программа поняла, что код после него является вложенным, необходимо обязательно сделать отступ в виде четырех пробелов. Обычно они ставятся автоматически, если пользователь работает в специально созданной среде программирования.
Заметим, что пользоваться клавишей Tab для создания отступа крайне нежелательно.
Ситуаций, в которых можно было бы применить условный оператор, великое множество. К ним, например, относится:
- Определение, сдал ли студент экзамен. При количестве верных ответов 10 из 15 – сдал, если меньше – не сдал;
- Выяснение размера скидки. Если купил 10 товаров – скидка 10%, если меньше – скидка не предоставляется.
Оператор if
С английского название этого оператора переводится, как «если». То есть он задает условие. После данного оператора записывается само выражение. Если оно оказывается истинным, то программа переходит к выполнению инструкции, заданной в указанном операторе. Выражение считается истинным, когда оно:
- не равно нулю;
- не является пустым;
- является логическим
Для ясности рассмотрим пример использования if — условия в Python 3:
if 3: print("Привет 3")
На экране перед пользователем появится запись: Привет 3.
a = 6 if a == 6: print("Привет 2")
На дисплее компьютера отобразится: Привет 2.
Также можно задать условие формулой или условным выражением:
a = 5 if a > 2: print("Привет 3")
Переменная равна 5, условие, чтобы она была больше 2. Оно истинное, поэтому перед нами появится: Привет 3.
Еще более сложный вариант с несколькими переменными:
a = 0 b = 34 c = 10 if c < 100: a = b + c print(a)
Поскольку с действительно меньше 100, а станет равным 44, и именно это число появится на дисплее при выполнении данного кода. Если бы с изначально было большее 100, например, 110, то на экране бы отобразился 0, переменная а просто не изменилась бы вообще.
Оператор else
Иногда программе нужно указать, что делать, если условие оказывается ложным. Для этого задается новый набор инструкций и используется конструкция if – else. Кстати, стоит запомнить, что в else не может быть никакого логического выражения. Также невозможна и ситуация, при которой выполнятся обе ветви (и if, и else).
a = 7 if a > 5: print("Да") else: print("Нет")
При выполнении данного кода на компьютере появится: Да. Это происходит, потому что 7 действительно больше заданной в условии цифры 5.
Посмотрим, что же случится, если условие станет ложным. Возьмем тот же код, но изменим переменную а.
a = 3 if a > 5: print("Да") else: print("Нет")
Очевидно, что перед пользователем появится слово «Нет», поскольку 3 не больше 5, а меньше.
product1 = 30 product2 = 23 if product1+ product2 > 70 : print("70 рублей не хватит") else: print("Денег хватает, все оплачено")
В данном случае программист увидит запись: Денег хватает, все оплачено, поскольку 30 + 23 = 53, а это меньше чем 70.
Оператор elif и конструкция if – elif – else
Вообще elif примерно расшифровывается, как else + if. Чтобы можно было реализовать программу, которая выбирала бы из нескольких альтернативных вариантов, используется указанная конструкция.
Рассмотрим код, в котором имеется несколько условий:
if balance < 0: print("Баланс ниже нуля, положите деньги на счет, чтобы Вам не выписали штраф") elif balance == 0: print("Баланс равен нулю, скорее внесите деньги на счет") else: print("Ваш баланс выше нуля, все хорошо")
Так, программа может рассмотреть варианты с тремя условиями. И если переменная balance будет равна 150, то перед пользователем появится надпись: Ваш баланс выше нуля, все хорошо.
Оператор elif позволяет упростить код. Сделать его легче читаемым. Позволяет избежать написание несколько условий if в Python.
Тернарный оператор
Иногда для сокращения записи используется так называемый тернарный оператор, благодаря ему код набирается в одну строку. Посмотрим на пример того, как можно записать условие Python в одну строку:
is_happy = True state = "happy" if is_happy else "not happy"
Чтобы не расписывать в несколько строк оператор if, просто используем сжатый вариант.
Конструкция switch – case
Данная инструкция в Python не используется. Вместо этого можно применять конструкции с несколькими elif. Например, программист хочет написать код, чтобы программа ставила оценку за пройденный студентами тест. При этом оценок может быть несколько. Тогда можно оформить так:
if grade >= 50: print("Оценка 5 с плюсом") elif grade >= 45: print("Оценка 5") elif grade >= 35: print("Оценка 4") elif grade >= 25: print("Оценка 3") else: print("Тест провален")
В этом случае значение переменной grade будет сравниваться со всеми условиями подряд. Однако когда условие станет истинным, выполнение кода остановится и на экране появится сообщение об оценке. Например, если grade равен 30, то на дисплей будет выведена надпись: Оценка 3; если же переменная будет ниже 25, то пользователь увидит: Тест провален.
Если начинающий программист успешно владеет условными конструкциями, это существенно облегчает написание программ и позволяет точнее обозначать их действия. Для усложнения можно создавать целые комбинации операторов, а также объединять их с помощью циклов.
Как сделать несколько условий в if и чтобы они все выполнялись?
Но вот загвоздка в if должны исполниться обе функции а оператор && проверяет сперва одну если там false то вторую даже не проверяет.
Обе функции возвращают true или false от результата работы. Но в них еще есть функционал который нужно исполнить в обеих независимо от результата.
Придумал варианты записать через запятую)) работает ну js все хавает не знаю правильно ли это.
Еще есть придумал вариант с умножением) true * true = 2 a true * true * false = 0
Еще есть мысль возвращать число 0 или 1 и потом считать сумму и если она равна количеству функций тогда все ок.
Ну это мои варианты. Гугл что то ничего не выдает полезного на этот счет..
Просто интересно есть какое вариант 100% правильный. Вызвать обе функции в if
- Вопрос задан более трёх лет назад
- 65019 просмотров
3 комментария
Простой 3 комментария
Python. Урок 5. Условные операторы и циклы
![]()
В этом уроке рассмотрим оператор ветвления if и операторы цикла while и for. Основная цель – это дать общее представление об этих операторах и на простых примерах показать базовые принципы работы с ними.
Условный оператор ветвления if
Оператор ветвления if позволяет выполнить определенный набор инструкций в зависимости от некоторого условия. Возможны следующие варианты использования.
1. Конструкция if
Синтаксис оператора if выглядит так.
if выражение: инструкция_1 инструкция_2 . инструкция_n
После оператора if записывается выражение. Если это выражение истинно, то выполняются инструкции, определяемые данным оператором. Выражение является истинным, если его результатом является число не равное нулю, непустой объект, либо логическое True. После выражения нужно поставить двоеточие “:”.
ВАЖНО: блок кода, который необходимо выполнить, в случае истинности выражения, отделяется четырьмя пробелами слева!
if 1: print("hello 1")
Напечатает: hello 1
a = 3 if a == 3: print("hello 2")
Напечатает: hello 2
a = 3 if a > 1: print("hello 3")
Напечатает: hello 3
lst = [1, 2, 3] if lst : print("hello 4")
Напечатает: hello 4
2. Конструкция if – else
Бывают случаи, когда необходимо предусмотреть альтернативный вариант выполнения программы. Т.е. при истинном условии нужно выполнить один набор инструкций, при ложном – другой. Для этого используется конструкция if – else.
if выражение: инструкция_1 инструкция_2 . инструкция_n else: инструкция_a инструкция_b . инструкция_x
a = 3 if a > 2: print("H") else: print("L")
a = 1 if a > 2: print("H") else: print("L")
Условие такого вида можно записать в строчку, в таком случае оно будет представлять собой тернарное выражение.
a = 17 b = True if a > 10 else False print(b)
В результате выполнения такого кода будет напечатано: True
3. Конструкция if – elif – else
Для реализации выбора из нескольких альтернатив можно использовать конструкцию if – elif – else.
if выражение_1: инструкции_(блок_1) elif выражение_2: инструкции_(блок_2) elif выражение_3: инструкции_(блок_3) else: инструкции_(блок_4)
a = int(input("введите число:")) if a 0: print("Neg") elif a == 0: print("Zero") else: print("Pos")
Если пользователь введет число меньше нуля, то будет напечатано “Neg“, равное нулю – “Zero“, большее нуля – “Pos“.
Оператор цикла while
Оператор цикла while выполняет указанный набор инструкций до тех пор, пока условие цикла истинно. Истинность условия определяется также как и в операторе if. Синтаксис оператора while выглядит так.
while выражение: инструкция_1 инструкция_2 . инструкция_n
Выполняемый набор инструкций называется телом цикла.
a = 0 while a 7: print("A") a += 1
Буква “А” будет выведена семь раз в столбик.
Пример бесконечного цикла.
a = 0 while a == 0: print("A")
Операторы break и continue
При работе с циклами используются операторы break и continue.
Оператор break предназначен для досрочного прерывания работы цикла while.
a = 0 while a >= 0: if a == 7: break a += 1 print("A")
В приведенном выше коде, выход из цикла произойдет при достижении переменной a значения 7. Если бы не было этого условия, то цикл выполнялся бы бесконечно.
Оператор continue запускает цикл заново, при этом код, расположенный после данного оператора, не выполняется.
a = -1 while a 10: a += 1 if a >= 7: continue print("A")
При запуске данного кода символ “А” будет напечатан 7 раз, несмотря на то, что всего будет выполнено 11 проходов цикла.
Оператор цикла for
Оператор for выполняет указанный набор инструкций заданное количество раз, которое определяется количеством элементов в наборе.
for i in range(5): print("Hello")
В результате “Hello” будет выведено пять раз.
Внутри тела цикла можно использовать операторы break и continue, принцип работы их точно такой же как и в операторе while.
Если у вас есть заданный список, и вы хотите выполнить над каждым элементом определенную операцию (возвести в квадрат и напечатать получившееся число), то с помощью for такая задача решается так.
lst = [1, 3, 5, 7, 9] for i in lst: print(i ** 2)
Также можно пройти по всем буквам в строке.
word_str = "Hello, world!" for l in word_str: print(l)
Строка “Hello, world!” будет напечатана в столбик.
На этом закончим краткий обзор операторов ветвления и цикла.
P.S.
Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме. Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.
Раздел: Python Уроки по Python Метки: Python, Уроки Python
Python. Урок 5. Условные операторы и циклы : 41 комментарий
- Ирина 23.09.2017 Подскажите, пожалуйста, что делать, если знаки” == “и “!=” не выделяются отдельным цветом и, соответственно, не дают никакого результата?
- writer Автор записи 24.09.2017 Приведите пример код пожалуйста!
- vitek 29.07.2018 print(“0 == False”)
- Максим 06.08.2018 Если верно понимаю, Вы не правильно записываете команду
Получается так, что Вы говорите программе, чтобы она описала строчное значение, указанное в “”
В данным случае, Вам нужно применить оператор if и написать:
if name == “0”:
print (“False”) Таким образом вы даете программе условие, что: если переменная равна значению “0” (строчному значению)
то выводи False
- writer 04.12.2018 Можно вот так:
>>> name=[“Иван”, “ваня”, “ванюша”]
>>> if “Иван” in name:
print(“hello!”) hello!
- rrrrr 21.10.2019 nope
- Илья 25.05.2020 def find_NOK(number1, number2):
if number1 < number2:
number1, number2 = number2, number1
for x in range(number2):
if number1*(x+1)%number2 == 0:
return number1*(x+1)
return number1*number2 a, b = map (int, input().split(', '))
print(find_NOK(a, b))
- writer 06.10.2019 Это l – от слова letter – буква. Хотя сейчас бы я поставил символ ‘c’ вместо нее.
- Айдар 09.02.2020 Решил проблему сам
- Jam 13.07.2020 Функция range генерирует все числа указанные в диапазоне не включая последнее.
Поэтому:
range(1, max(a) + 1)
- Надыр 30.08.2020 Там f==5