8

我使用 pycharm 和几次使用if语句时,我看到了使用德摩根定律更改语句的建议,例如使用以下if语句:

if new_odds > 10 and new_odds <= 30:

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

对我来说,它的可读性降低了,那么使用德摩根定律有什么好处,还是严格来说是个人选择?

4

5 回答 5

17

德摩根的法律规定

"not (A and B)" 与 "(not A) or (not B)" 相同

并且,

"not (A or B)" 与 "(not A) and (not 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不是< max_health最大值。

虽然是人为的,但这向我们表明,德摩根定律是使我们能够重写逻辑的工具。是否改进此逻辑取决于程序员,但其目的是能够产生更简单的结构,首先更具可读性,其次并希望需要更少的指令,从而更快。

于 2014-01-23T23:32:23.893 回答
7

在 Python 中,清晰几乎总是比稍微快一点要好(如果那样的话,我对此表示怀疑)。

我更喜欢这个更简单的陈述:

if 10 < new_odds <= 30:
于 2014-01-23T22:51:13.410 回答
5

在某些情况下,它使事情变得更加冗长和可读。但是,如果您已经有一堆nots 散布在周围,或者您正在以不自然的顺序比较事物,则分解可以减少nots 的数量或颠倒不相等比较的顺序。例如:

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)

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

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


一些语言(逻辑、约束满足、关系等)不是这样,因为将 anot应用于一个值不仅是翻转 True 和 False,而且会产生相反的结果,可能慢得多,甚至可能不确定,查询。

但 Python 或大多数其他“通用”语言并非如此。

于 2014-01-23T22:51:22.103 回答
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
于 2014-01-23T23:00:34.820 回答
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:

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

于 2014-01-23T22:55:03.753 回答