这两行代码有什么区别:
if not x == 'val':
和
if x != 'val':
一个比另一个更有效吗?
会更好用吗
if x == 'val':
pass
else:
这两行代码有什么区别:
if not x == 'val':
和
if x != 'val':
一个比另一个更有效吗?
会更好用吗
if x == 'val':
pass
else:
Answers:
使用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
最后,也许是最重要的一点:通常,两者在逻辑上是相同的,x != y
但比更具可读性not x == y
。
__eq__
与不一致的类都会__ne__
被彻底破坏。
not x == y
。当我将代码放入时if
,结果表明它们都具有相同数量的指令,而一条指令POP_JUMP_IF_TRUE
和另一条指令是相同的POP_JUMP_IF_FALSE
(这是它们之间的唯一区别,只是使用了不同的COMPARE_OP
)。当我在不带if
s的情况下编译代码时,我得到了您所得到的。
==
和!=
不互斥的另一个示例是涉及null
值的类似SQL的实现。在SQL null
不会返回true
到!=
比其他任何价值,所以SQL接口Python实现也可能有同样的问题。
not ==
和之间的可能差异!=
,这似乎是我回答中最有趣的部分!我不认为这是讲究是否,为什么以及何时有意义的地方-参见例如Python为什么具有__ne__
操作符方法而不是正义方法__eq__
?
@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事件探查器结果:
因此,我们可以看到有间〜0.7%的非常微小差别if not x == 'val':
和if x != 'val':
。其中,if x != 'val':
是最快的。
但是,最令人惊讶的是,我们可以看到
if x == 'val':
pass
else:
实际上是最快的,胜过if x != 'val':
〜0.3%。这不是很容易理解,但是我想如果您想忽略不计的性能改进,可以采用这种方法。
在第一个Python中,Python必须执行比必要更多的操作(而不是仅检查不等于它,而是必须检查它是否相等,因此还要执行一个操作)。不可能说出一次执行的区别,但是如果执行多次,第二次执行将更有效率。总的来说,我会用第二个,但从数学上讲它们是相同的
>>> 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':
但是!=
作为一个相反的运算符,可以更好地理解==
它。
not
操作员是动态的”?
我想在上面扩展我的可读性注释。
再次,我完全同意可读性优先于其他(性能无关紧要)的问题。
我想指出的是,大脑对“阳性”的解释比对“阴性”的解释要快。例如,“停止”与“不走”(由于单词数量的差异,这是一个很糟糕的例子)。
因此有一个选择:
if a == b
(do this)
else
(do that)
在功能上等效于:
if a != b
(do that)
else
(do this)
较低的可读性/可理解性导致更多的错误。也许不是在初始编码中,而是(不如您聪明!)维护发生了变化...