Python如果不是== vs if!=

这两行代码有什么区别:

if not x == 'val': 

 if x != 'val': 

比另一个更有效率吗?

使用会更好吗?

 if x == 'val': pass else: 

使用dis查看为这两个版本生成的字节码:

not ==

  4 0 LOAD_FAST 0 (foo) 3 LOAD_FAST 1 (bar) 6 COMPARE_OP 2 (==) 9 UNARY_NOT 10 RETURN_VALUE 

!=

  4 0 LOAD_FAST 0 (foo) 3 LOAD_FAST 1 (bar) 6 COMPARE_OP 3 (!=) 9 RETURN_VALUE 

后者的运作较less,因此效率可能稍高。


在 commments (thanks, @Quincunx )中指出, if foo != barif not foo == bar ,那么操作次数完全相同,只是COMPARE_OP更改, POP_JUMP_IF_TRUE更改为POP_JUMP_IF_FALSE

not ==

  2 0 LOAD_FAST 0 (foo) 3 LOAD_FAST 1 (bar) 6 COMPARE_OP 2 (==) 9 POP_JUMP_IF_TRUE 16 

!=

  2 0 LOAD_FAST 0 (foo) 3 LOAD_FAST 1 (bar) 6 COMPARE_OP 3 (!=) 9 POP_JUMP_IF_FALSE 16 

在这种情况下,除非每次比较所需的工作量有所不同,否则根本不可能看到任何性能差异。


但是请注意,这两个版本在逻辑上并不总是相同的 ,因为这取决于__eq____ne__的实现。 根据数据模型文档 :

比较运算符之间没有隐含的关系。 x==y的真值并不意味着x!=y是错误的。

例如:

 >>> class Dummy(object): def __eq__(self, other): return True def __ne__(self, other): return True >>> not Dummy() == Dummy() False >>> Dummy() != Dummy() True 

最后,也许最重要的是:一般来说,两者逻辑上是相同的, x != ynot x == y更可读

@jonrsharpe有一个很好的解释是怎么回事。 我想我只是在运行10,000,000次的3个选项中的每一个时显示不同的时间(足以显示一个微小的差异)。

使用的代码:

 def a(x): if x != 'val': pass def b(x): if not x == 'val': pass def c(x): if x == 'val': pass else: pass x = 1 for i in range(10000000): a(x) b(x) c(x) 

和cProfile分析器结果:

在这里输入图像说明

所以我们可以看到, if not x == 'val':if x != 'val': 其中, if x != 'val':是最快的。

但是,最令人惊讶的是,我们可以看到

 if x == 'val': pass else: 

实际上是最快的, if x != 'val': 〜0.3%,就会跳动。 这不是很可读,但我想如果你想要一个可以忽略不计的性能改进,可以走这条路。

在第一个中,Python必须执行多于一个的操作(而不是仅仅检查不等于必须检查它是否是相等的,因此还有一个操作)。 从一次执行中分辨出来是不可能的,但如果多次执行,第二次执行效率会更高。 总的来说,我会用第二个,但在math上它们是一样的

 >>> from dis import dis >>> dis(compile('not 10 == 20', '', 'exec')) 1 0 LOAD_CONST 0 (10) 3 LOAD_CONST 1 (20) 6 COMPARE_OP 2 (==) 9 UNARY_NOT 10 POP_TOP 11 LOAD_CONST 2 (None) 14 RETURN_VALUE >>> dis(compile('10 != 20', '', 'exec')) 1 0 LOAD_CONST 0 (10) 3 LOAD_CONST 1 (20) 6 COMPARE_OP 3 (!=) 9 POP_TOP 10 LOAD_CONST 2 (None) 13 RETURN_VALUE 

在这里你可以看到not x == y有一个比x != y更多的指令。 所以在大多数情况下,性能的差异将会非常小,除非你进行了数百万次的比较,即使这样做也可能不是瓶颈的原因。

还有一点需要注意,因为其他的答案大部分是正确的,如果一个类只定义了__eq__()而不是__ne__() ,那么你的COMPARE_OP (!=)会运行__eq__()并且否定它。 那时候,你的第三个select可能会更有效一些,但是如果你需要这个速度的话,应该只考虑这个速度,因为很难快速理解。

这是关于你阅读的方式。 not运营商是dynamic的,这就是为什么你能够应用它

 if not x == 'val': 

但是!=可以在一个更好的上下文中作为一个与==做相反的操作符来读取。

我想展开上面的可读性评论。

再一次,我完全同意可读性覆盖其他(performance无关紧要的)关注。

我想指出的是,大脑对“积极”的解释比对“消极”的解释要快。 例如,“停止”与“不要走”(由于单词数量的不同,一个比较糟糕的例子)。

所以给出一个select:

 if a == b (do this) else (do that) 

比function上等同的更好:

 if a != b (do that) else (do this) 

可读性/易懂性降低会导致更多的错误。 也许不是在最初的编码,但(不是你聪明!)维护更改…