Пожалуй, одно из самых непонятных явлений при анализе чужого кода для новичков - это наличие в нем тернарных логических операций. Они выглядят пугающе, и зачастую вовсе не очевидно, как они работают. Это мешает интерпретировать и анализировать код "глазами". Однако, если в них разобраться - это повысит качество вашего кода, и позволит вам усовершенствовать Ваш навык поиска ошибок.
Давайте разбираться, что это, и зачем:
Определение:
Тернарная логическая операция - это операция условного присваивания значения переменной. Т.е. в зависимости от выполнения условия присваивания, переменная примет либо одно, либо другое значение.
Структура тернарной логической операции:
Как мы привыкли писать подобные кейсы:
Здесь, если результат some_function_result() будет меньше 3, то переменная a примет значение 5, во всех остальных случаях она останется в значении 3
Тот же код можно записать в виде тернарной операции:
Разбираемся:
В начале python выполнит условие тернарной операции (some_function_result() < 3). Если оно истинно(True) - переменной a будет присвоено значение, лежащее до условного оператора if (5), если же оно ложно(False) - значение, лежащее после условного оператора else (3)
Тернарные логические операции можно встретить в связке со списковыми включениями, и окончательно запутаться, где и что выполняется.
объясню на примере такого когда:
Здесь мы видим сразу два условия if, при этом первое относится к работе с итератором, и представляет тернарную логическую операцию (возвести значение в квадрат при условии делимости этого значения на 5, во всех остальных случаях не возводить, но работать только с четными значениями из списка от 0 до 100 (условие спискового включения, отфильтровывающее итерации с ложным условием (нечетные числа)).
В данном коде вначале выполняется обработка спискового включения [i for i in range(100) if not i%2], и для каждого полученного таким образом i, выполняется тернарная логическая операция i = i**2 if i%5 else i
Так же можно встретить вложенность тернарных логических операций:
Главенство операций и их вложенность определяется интерпретатором как и в случае списковых включений слева направо.
Таким образом сначала вычислится some_func(). Если оно истинно - то var = 3, если ложно, то var = 5 if some_func2() else 8 - уже знакомая нам обычная тернарная операция.
Вложенность операций может быть теоретически бесконечной.
У тернарной логической операции существует еще одна, более непонятная запись:
т.е. для уже приведенного примера, такая нотация выглядит как:
Однако, прошу обратить внимание, что разные здесь не только записи, но и логика работы.
В тех случаях, когда значения вычисляемы, а не задаваемы - в первом случае вычисляется только одно значение в зависимости от условия, а во втором - вычисляются оба. Это можно проиллюстрировать на примере ошибочного вычисления с заведомо верным условием:
При этом, несмотря на наличие ошибки DivisionByZero - первая строка отработает корректно, поскольку значение после else не будет вычисляться по причине истинности условия
Вторая же строка вернет вам ошибку вычисления (DivizonByZero) - поскольку кортеж должен содержать конечные значения для присваивания, и перед логической операцией он должен быть вычислен.
Учитывайте, пожалуйста, эти нюансы в своих разработках
Так же есть сокращенная запись тернарной логической операции, связанная с приведением результата выполнения функции к булевой величине:
Это не совсем тернарная операция. По сути, она всегда присвоит переменной a возвращаемое значение some_func, если только some_func не вернула False,0 или None.
Следует очень осторожно использовать такую конструкцию при работе с числами, поскольку число "0" является булевым False даже если это логичный и разумный результат вычисления some_func в этом случае a примет значение 5.
На этом с тернарной операцией покончено. Надеюсь, в ее логике вы разобрались, и, встретив ее в коде - будете во всеоружии)
Давайте разбираться, что это, и зачем:
Определение:
Тернарная логическая операция - это операция условного присваивания значения переменной. Т.е. в зависимости от выполнения условия присваивания, переменная примет либо одно, либо другое значение.
Структура тернарной логической операции:
Python:
var = значение_если_условие_истинно if условие else значение_если_условие_ложно
Как мы привыкли писать подобные кейсы:
Python:
a = 3
b = some_function_result()
if b < 3:
a = 5
Тот же код можно записать в виде тернарной операции:
Python:
a = 5 if some_function_result() < 3 else 3
Разбираемся:
В начале python выполнит условие тернарной операции (some_function_result() < 3). Если оно истинно(True) - переменной a будет присвоено значение, лежащее до условного оператора if (5), если же оно ложно(False) - значение, лежащее после условного оператора else (3)
Тернарные логические операции можно встретить в связке со списковыми включениями, и окончательно запутаться, где и что выполняется.
объясню на примере такого когда:
Python:
some_lst = [i**2 if i%5 else i for i in range(100) if not i%2]
В данном коде вначале выполняется обработка спискового включения [i for i in range(100) if not i%2], и для каждого полученного таким образом i, выполняется тернарная логическая операция i = i**2 if i%5 else i
Так же можно встретить вложенность тернарных логических операций:
Python:
var = 3 if some_func() else 5 if some_func2() else 8
Таким образом сначала вычислится some_func(). Если оно истинно - то var = 3, если ложно, то var = 5 if some_func2() else 8 - уже знакомая нам обычная тернарная операция.
Вложенность операций может быть теоретически бесконечной.
У тернарной логической операции существует еще одна, более непонятная запись:
Код:
var = (если_условие_ложно, если_условие_истинно)[условие]
т.е. для уже приведенного примера, такая нотация выглядит как:
Python:
a = (5,3)[some_function_results() < 3]
Однако, прошу обратить внимание, что разные здесь не только записи, но и логика работы.
В тех случаях, когда значения вычисляемы, а не задаваемы - в первом случае вычисляется только одно значение в зависимости от условия, а во втором - вычисляются оба. Это можно проиллюстрировать на примере ошибочного вычисления с заведомо верным условием:
Python:
a = 10*2 if 3 < 5 else 10/0
b = (10/0, 10*2)[3<5]
Вторая же строка вернет вам ошибку вычисления (DivizonByZero) - поскольку кортеж должен содержать конечные значения для присваивания, и перед логической операцией он должен быть вычислен.
Учитывайте, пожалуйста, эти нюансы в своих разработках
Так же есть сокращенная запись тернарной логической операции, связанная с приведением результата выполнения функции к булевой величине:
Python:
a = some_func() or 5
Следует очень осторожно использовать такую конструкцию при работе с числами, поскольку число "0" является булевым False даже если это логичный и разумный результат вычисления some_func в этом случае a примет значение 5.
На этом с тернарной операцией покончено. Надеюсь, в ее логике вы разобрались, и, встретив ее в коде - будете во всеоружии)
Последнее редактирование: