Разница между вложенным оператором if и логическими конструкциями
Вот есть ли например отличие между
if condition1 and condition2:
и
if condition1:
if condition2:
Например, задачу определить делится ли число на 3 и/или на 5 можно решить:
num = 10
if num % 3 == 0 and num % 5 == 0:
print('Число делится на 3 и на 5')
elif num % 3 != 0 and num % 5 != 0:
print('Число не делится на 3 и на 5')
elif num % 3 != 0 and num % 5 == 0:
print('Число не делится на 3 но делится на 5')
else:
print('Число делится на 3 и не делится на 5')
Или же:
if num % 3 == 0:
if num % 5 == 0:
print('Число делится на 3 и на 5')
else:
print('Число делится на 3, но не на 5')
else:
if num % 5 == 0:
print('Число делится на 5, но не на 3')
else:
print('Число не делиться ни на 5 ни на 3')
В каких ситуациях следует использовать тот или иной подход и есть ли какая-то разница между этими вариантами?
Ответы (5 шт):
Между двумя верхними вариантами нет логической разницы. Но есть разница с точки зрения "питоничности" - в одну строку правильнее, так как яснее.
Выбирая между вашими вариантами решения задачи для ясности я бы выбрал верхний вариант.
Но надо учесть, что нижний вариант работать будет значительно быстрее, поэтому при использовании в варианте с длительными вычислениями выбрать надо его.
Я бы решал её короче для той же "питоничности", фразы чуть длиннее будут, правда:-) Можно, конечно, поперебирать фразы, чтобы ближе к образцу были.
num = 10
v3 = 'не ' if num % 3 else ''
v5 = 'не ' if num % 5 else ''
print ('Число '+ v3 + 'делится на 3 и ' + v5 + 'делится на 5')
В Вашем варианте можно сделать и так, и так. Тут вопрос больше в читаемости кода. При сложных ветвлениях можно упустить какой-то из вариантов.
Можно, к примеру, организовывать кейсы с ответами через словари. Так код, на мой взгляд, будет выглядеть немного более читаемым.
num = 3
res = {(num % 3 == 0 and num % 5 == 0): 'Число делится на 3 и на 5',
(num % 3 != 0 and num % 5 != 0): 'Число не делится на 3 и на 5',
(num % 3 != 0 and num % 5 == 0): 'Число не делится на 3 но делится на 5',
(num % 3 == 0 and num % 5 != 0): 'Число делится на 3 и не делится на 5'}[True]
print(res)
Тут условия особо ничего не меняют, код сильно лучше не становится, в обоих случаях много однотипных повторяющихся кусков. Как вариант можно сделать так:
num = int(input("Введите число:"))
x, y = 3, 5
div_by_x = num % x == 0
div_by_y = num % y == 0
if div_by_x and div_by_y:
print(f'Число делится на {x} и на {y}')
elif not div_by_x and not div_by_y:
print(f'Число не делиться ни на {x}, ни на {y}')
else:
if div_by_y:
x, y = y, x
print(f'Число делится на {x}, но не на {y}')
Предложу свой вариант со словарем. Почему мне не нравится вариант ТС: в каждой ветке if вы делаете вычисления. Мое желание вычислять только один раз и хранить готовые результаты
num = 10
dict_ = {
3: "не делится на 3" if num % 3 else "делится на 3",
5: "не делится на 5" if num % 5 else "делится на 5",
}
print(f"Число {dict_[3]} и {dict_[5]}")
Играться можно долго и по разному, вплоть до совсем фантастических вариантов. Но по большей части нет разницы сколько много и как глубоко уходят ветвления if. Основное, на мой взгляд, - это читаемость. Часто вижу, как возможность записать в одну строку всю логику, убивает понимаемость/читаемость кода.
UPD
После некоторых экспериментов со скоростью выполнения могу резюмировать, что сама конструкция if при большом масштабировании процесса (в 10^6 и 10^9 раз) на скорость почти не влияет. Выяснил, что данное решение проигрывает в скорости только по причине использования форматирования через f-строку. Поэтому, с простыми арифметическими операциями, как у вас, нет смысла отдавать предпочтение той или иной конструкции, поскольку разница во времени мизерна. Остаемся в понятиях читаемости и удобства использования
Второй вариант будет быстрее, но так как (просто несоизмеримо) большую часть времени будет занимать ввод/вывод, это не так уж важно в этой задаче. Важнее читабельность кода.
И здесь плюсы и минусы есть у обоих вариантов. Сильно вложенные лесенки обычно читаются сложнее, но квадратный код, состоящий из массивных, почти одинаковых строк кода с минимальными различиями, заставляет очень внимательно вчитываться, чтобы не упустить детали.
В свежих версиях python (>= 3.10) можно сделать так
match num % 3, num % 5:
case 0, 0:
print('Число делится на 3 и на 5')
case 0, _:
print('Число делится на 3, но не делится на 5')
case _, 0:
print('Число не делится на 3, но делится на 5')
case _:
print('Число не делится ни на 3, ни на 5')
Этот вариант еще медленнее, но, на мой взгляд, в читабельности выигрывает.