Python if not == 与 if !=

问题描述 投票:0回答:7

这两行代码有什么区别:

if not x == 'val':

if x != 'val':

其中一个比另一个更有效率吗?

用起来会更好吗

if x == 'val':
    pass
else:
python if-statement equality
7个回答
242
投票

使用

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   

后者的操作较少,因此可能稍微更高效。


有人在评论中指出(谢谢,@Quincunx),if foo != bar

if 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
    

32
投票
@jonrsharpe 对正在发生的事情有一个很好的解释。我想我只是显示运行 3 个选项中的每一个 10,000,000 次时的时间差异(足以显示细微的差异)。

使用的代码:

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 分析器结果:

enter image description here

因此我们可以看到

if not x == 'val':

if x != 'val':
 之间存在约 0.7% 的微小差异。其中,
if x != 'val':
 是最快的。

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

if x == 'val': pass else:

实际上是最快的,比

if x != 'val':

 快约 0.3%。这不是很可读,但我想如果您想要微不足道的性能改进,可以沿着这条路线走下去。


7
投票
在第一个中,Python 必须多执行一次不必要的操作(而不是仅仅检查不等于,它必须检查是否不等于,从而多执行一次操作)。一次执行无法区分出差异,但如果运行多次,第二次执行的效率会更高。总的来说,我会使用第二个,但从数学上来说它们是相同的


6
投票
附加说明,由于其他答案大多正确地回答了您的问题,如果一个类仅定义

__eq__()

 而不是 
__ne__()
,那么您的 
COMPARE_OP (!=)
 将运行 
__eq__()
 并否定它。那时,您的第三个选择可能会更有效一点,但只有在您需要速度时才应考虑,因为它很难快速理解。


5
投票
>>> 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
多了一条指令。因此,在大多数情况下,性能差异将非常小,除非您进行数百万次比较,即使这样,这也可能不会成为瓶颈的原因。 


3
投票
这与您的阅读方式有关。

not

 运算符是动态的,这就是为什么您能够在 
中应用它

if not x == 'val':

但是

!=

 可以在更好的上下文中被理解为一个与 
==
 所做的相反的操作符。


1
投票
我想扩展我上面的可读性评论。

再次,我完全同意可读性高于其他(性能无关紧要的)问题。

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

所以有一个选择:

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

优于功能等效的:

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

可读性/可理解性较低会导致更多错误。 也许不是在最初的编码中,而是(不像你那么聪明!)维护更改......

© www.soinside.com 2019 - 2024. All rights reserved.