这两行代码有什么区别:
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
后者的操作较少,因此可能稍微更高效。
有人在评论中指出(谢谢,@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
使用的代码:
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':
之间存在约 0.7% 的微小差异。其中,
if x != 'val':
是最快的。然而,最令人惊讶的是,我们可以看到
if x == 'val':
pass
else:
实际上是最快的,比
if x != 'val':
快约 0.3%。这不是很可读,但我想如果您想要微不足道的性能改进,可以沿着这条路线走下去。
__eq__()
而不是
__ne__()
,那么您的
COMPARE_OP (!=)
将运行
__eq__()
并否定它。那时,您的第三个选择可能会更有效一点,但只有在您需要速度时才应考虑,因为它很难快速理解。
>>> 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
多了一条指令。因此,在大多数情况下,性能差异将非常小,除非您进行数百万次比较,即使这样,这也可能不会成为瓶颈的原因。
not
运算符是动态的,这就是为什么您能够在中应用它
if not x == 'val':
但是
!=
可以在更好的上下文中被理解为一个与
==
所做的相反的操作符。
再次,我完全同意可读性高于其他(性能无关紧要的)问题。
我想指出的是,大脑解释“积极”的速度比解释“消极”的速度要快。 例如,“停止”与“不要走”(由于单词数量的差异,这是一个相当糟糕的例子)。
所以有一个选择:
if a == b
(do this)
else
(do that)
优于功能等效的:
if a != b
(do that)
else
(do this)
可读性/可理解性较低会导致更多错误。 也许不是在最初的编码中,而是(不像你那么聪明!)维护更改......