在python中使用De Morgan定律有什么好处吗?

时间:2014-01-23 22:49:22

标签: python demorgans-law

我在使用if语句时使用pycharm几次我看到了使用De Morgan法则更改语句的建议,例如使用以下if语句:

if new_odds > 10 and new_odds <= 30:

if not (not (new_odds > 10) or not (new_odds <= 20)):

对我而言,它的可读性较差,使用De Morgan法律有什么优势,还是严格来说是个人选择?

5 个答案:

答案 0 :(得分:16)

De Morgan's laws声明:

  

“不(A和B)”与“(不是A)或(不是B)”

相同      

还有,

     

“not(A或B)”与“(不是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))

根据De Morgan的定律,我可以分解这个:

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的反面是< max_health,否则不是最大值。

虽然做作,但这向我们表明, De Morgan的法律是使我们能够重写逻辑的工具。这种逻辑是否得到改进取决于程序员,但目的是能够生成更简单的结构,这些结构首先更具可读性,其次希望需要更少的指令,因此更快。

答案 1 :(得分:7)

在Python中,显然总是更清楚,而不是稍微快一点(如果是这样,我怀疑)。

我更喜欢这个更简单的语句:

if 10 < new_odds <= 30:

答案 2 :(得分:5)

在某些情况下,它会使事情更加冗长和可读。但是,如果你已经散布了一堆not,或者你以不太自然的顺序比较事物,那么demorganing可以减少not的数量或反向不平等比较的顺序。例如:

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)

(第二个问题值得商榷......但这正是你对可读性和风格问题的期望。)

因此,如果它使您的代码更具可读性,那就去做吧;否则,不要。


少数语言(逻辑,约束 - 满足,关系等),但这不是真的,因为将not应用于某个值不仅仅是翻转真与假,但生成一个相反的,可能更慢,甚至可能是不确定的查询。

但是,对于Python或大多数其他“通用”语言来说情况并非如此。

答案 3 :(得分:2)

鉴于下面的结果,似乎更复杂/更不易读的表达也是最慢的。在任何情况下,可读性大多数时候在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

答案 4 :(得分:1)

它有时对于可读性很有用,但在执行时却是一样的。例如:

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:

此语法对于检查数值是否在特定范围内非常有用。