Python如果不是== vs如果!=


183

这两行代码有什么区别:

if not x == 'val':

if x != 'val':

一个比另一个更有效吗?

会更好用吗

if x == 'val':
    pass
else:

101
更好的是您可以阅读的内容,我怀疑您的程序的瓶颈会在这里
Thomas Ayoub 2015年

1
这个问题使我对“列表中没有x”和“列表中没有x”感兴趣
SomethingSomething

5
@SomethingSomething它们的解释是相同的。
jonrsharpe

4
我上面的评论的@SomethingSomething参考:stackoverflow.com/q/8738388/3001761
jonrsharpe 2015年

1
@Something这些东西也一样;这就是语法的解释方式,两个操作数是什么都无所谓。
jonrsharpe

Answers:


229

使用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 != 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 != y但比更具可读性not x == y


29
在实践中,任何__eq__与不一致的类都会__ne__被彻底破坏。
凯文

8
请注意,又有另一条指令并不总是正确的not x == y。当我将代码放入时if,结果表明它们都具有相同数量的指令,而一条指令POP_JUMP_IF_TRUE和另一条指令是相同的POP_JUMP_IF_FALSE(这是它们之间的唯一区别,只是使用了不同的COMPARE_OP)。当我在不带ifs的情况下编译代码时,我得到了您所得到的。
贾斯汀

1
==!=不互斥的另一个示例是涉及null值的类似SQL的实现。在SQL null不会返回true!=比其他任何价值,所以SQL接口Python实现也可能有同样的问题。

我开始希望我没有提到not ==和之间的可能差异!=,这似乎是我回答中最有趣的部分!我不认为这是讲究是否,为什么以及何时有意义的地方-参见例如Python为什么具有__ne__操作符方法而不是正义方法__eq__
jonrsharpe 2015年

29

@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%。这不是很容易理解,但是我想如果您想忽略不计的性能改进,可以采用这种方法。


31
希望所有人都知道不要对这些信息采取行动!进行不可读的更改以实现0.3%的改进-甚至达到10%的改进-很少是一个好主意,而这种改进很可能是渐逝的(而且不是很好:在Python运行时中进行非常小的更改)可以消除甚至逆转的任何增益。
马伏里奥

1
@Malvolio另外,Python 有不同的实现
Cees Timmerman 2015年

6

在第一个Python中,Python必须执行比必要更多的操作(而不是仅检查不等于它,而是必须检查它是否相等,因此还要执行一个操作)。不可能说出一次执行的区别,但是如果执行多次,第二次执行将更有效率。总的来说,我会用第二个,但从数学上讲它们是相同的


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。因此,除非您进行数百万次比较,否则在大多数情况下,性能差异将很小,即使这样,也可能不会成为瓶颈。


5

另一个需要注意的是,由于其他答案大多可以正确回答您的问题,因此,如果仅定义一个类__eq__()而不是__ne__(),则您COMPARE_OP (!=)将运行__eq__()并取反它。到那时,您的第三个选择可能会更有效率,但只有在需要速度时才应考虑使用,因为这很难快速理解。


3

这是关于您的阅读方式。not操作符是动态的,这就是为什么您可以将其应用于

if not x == 'val':

但是!=作为一个相反的运算符,可以更好地理解==它。


3
您是什么意思not操作员是动态的”
jonrsharpe 2015年

1
@jonrsharpe我认为他的意思是“非x”将调用x .__ bool __()[python 3-python 2使用非零 ]并恢复结果(请参阅docs.python.org/3/reference/datamodel.html#object。 __bool__
jdferreira

1

我想在上面扩展我的可读性注释。

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

我想指出的是,大脑对“阳性”的解释比对“阴性”的解释要快。例如,“停止”与“不走”(由于单词数量的差异,这是一个很糟糕的例子)。

因此有一个选择:

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

在功能上等效于:

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

较低的可读性/可理解性导致更多的错误。也许不是在初始编码中,而是(不如您聪明!)维护发生了变化...


1
大脑对“阳性”的解释比对“阴性”的解释要快,这是从经验中得出的,还是您读过有关此方面的研究?我只是问,因为根据(执行此操作)或(执行该操作)中的代码,我发现!= b更容易理解。
lafferc
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.