Есть ли какие-либо преимущества в использовании законов де Моргана в python?
Я использую pycharm и несколько раз при использовании if
утверждения я видел предложение изменить утверждение, используя законы де Моргана, например, со следующим if
о себе:
if new_odds > 10 and new_odds <= 30:
if not (not (new_odds > 10) or not (new_odds <= 20)):
для меня это делает его менее читаемым, так есть ли какие-либо преимущества в использовании законов де Моргана или это строго личный выбор?
5 ответов
законы де Моргана указано следующее:
"не (A и B)" и "(не А) или (не б)"
и
"не (А или Б)" - это то же самое, что"(не А) и (не б)"
, которые используются для преобразования логики между альтернативными формами. Поэтому, хотя трансформация, которую вы сделали, соответствует законам де Моргана, ее стало труднее читать. Как другие предложили многое проще 10 < new_odds <= 30
было бы гораздо более читаемым, очень важно понимать, что это сокращение для 10 < new_odds and new_odds <= 30
, потому что исходя из этого вы можете сделать логику типа:
10 < new_odds <= 30 != max_odds | default_condition
, который расширяется:
10 < new_odds and new_odds <= 30 and 30 != max_odds and max_odds | default_condition
Итак, имея в виду этот синтаксический сахар, давайте посмотрим на другой пример:
мы рассмотрим надуманный пример в простой ролевой игре, где мы смотрим на навык, который мы будем называть "голландское мужество". Предпосылка этого нападения это то, что вы можете бонус, если у вас максимальное здоровье, и либо ваша броня, либо ваш рейтинг атаки недостаточны для атаки врага. Мне нужно знать, когда это правило не применяется.
написание этого у нас есть 4 условия:
A = health == max_health
B = armor > enemy.attack
C = attack > enemy.defense
no_bonus = not(A and not(B and C))
используя законы де Моргана, я могу разложить это так:
not(A and not(B and C))
not(A) or not(B and C)
not(A) or not(B) or not(C)
not(health == max_health) or not(armor > enemy.attack) or (attack > enemy.defense)
Ну, теперь я могу разложить это дальше...
health < max_meath or armor < enemy.attack < attack > enemy.defense
здесь мы предполагаем противоположное == max_health
is < max_health
в противном случае его не максимальный.
хотя надуманный, это показывает нам, что законы де Моргана-это инструмент, позволяющий нам переписать логику. Улучшена ли эта логика или нет, зависит от программиста, но цель состоит в том, чтобы иметь возможность создавать более простые конструкции, которые, во-первых, более читабельны, а во-вторых, и, надеюсь, требуют меньше инструкций и, следовательно, быстрее.
в Python это почти всегда лучше быть ясным, чем немного быстрее (если это даже было бы, в чем я сомневаюсь).
Я предпочитаю этот еще проще о себе:
if 10 < new_odds <= 30:
В некоторых случаях, это делает вещи более подробный и четкий. Однако в случаях, когда у вас уже есть куча not
s разбросаны вокруг, или где вы сравниваете вещи в менее чем естественном порядке, demorganing может уменьшить количество not
s или обратный порядок неравных сравнений. Например:
if not foo() and not bar():
if not(foo() or bar()):
if new_score <= high_score and new_level <= high_level:
if not (new_score > high_score or new_level > high_level)
(второй спорный... но это именно то, что вы ожидаете от вопроса читаемости и стиля.)
так, если это делает ваш код более читаемый, сделайте это; в противном случае не делайте.
здесь are нескольких языков (логика, ограничение-удовлетворение, реляционной и т. д.) где это не так, потому что применение not
значение не просто переворачивает True и False, но генерирует обратный, возможно, намного медленнее или, возможно, даже неопределенный запрос.
но это не относится к Python или большинству других языков "общего назначения".
учитывая приведенные ниже результаты, кажется, что более сложное/менее читаемое выражение также является самым медленным. В любом случае читаемость большую часть времени более ценна в python.
In [1]: new_odds = 0
In [2]: %timeit if new_odds > 10 and new_odds <= 30: pass
10000000 loops, best of 3: 24.3 ns per loop
In [3]: %timeit if not (not (new_odds > 10) or not (new_odds <= 20)): pass
10000000 loops, best of 3: 48.6 ns per loop
In [4]: %timeit if 10 < new_odds <= 30:pass
10000000 loops, best of 3: 43.4 ns per loop
In [5]: new_odds = 20
In [6]: %timeit if new_odds > 10 and new_odds <= 30: pass
10000000 loops, best of 3: 57.7 ns per loop
In [7]: %timeit if not (not (new_odds > 10) or not (new_odds <= 20)): pass
10000000 loops, best of 3: 102 ns per loop
In [8]: %timeit if 10 < new_odds <= 30:pass
10000000 loops, best of 3: 52.7 ns per loop
это может быть полезно иногда для удобочитаемости, но это то же самое при выполнении. Например:
not(A AND B) === not(A) OR not(B)
if not a() and not b():
if not(a() or b()):
исполнение будет таким же с a()
True или False.
для вашего примера лучшим решением остается использовать мощь синтаксиса Python и написать:
if 10 < new_odds <= 30:
этот синтаксис чрезвычайно полезен для проверки того, что числовое значение находится в определенном диапазоне.