如果不是Python == vs if!=

laf*_*erc 175 python if-statement equality

这两行代码有什么区别:

if not x == 'val':
Run Code Online (Sandbox Code Playgroud)

if x != 'val':
Run Code Online (Sandbox Code Playgroud)

一个比另一个更有效吗?

使用会更好吗?

if x == 'val':
    pass
else:
Run Code Online (Sandbox Code Playgroud)

jon*_*rpe 221

使用dis一下两个版本生成的字节码:

not ==

  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 UNARY_NOT           
             10 RETURN_VALUE   
Run Code Online (Sandbox Code Playgroud)

!=

  4           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 RETURN_VALUE   
Run Code Online (Sandbox Code Playgroud)

后者的操作较少,因此可能稍微提高效率.


有人指出,在commments(感谢,@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
Run Code Online (Sandbox Code Playgroud)

!=

  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 POP_JUMP_IF_FALSE       16
Run Code Online (Sandbox Code Playgroud)

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


但请注意,这两个版本在逻辑上并不总是相同,因为它将取决于所讨论对象的实现__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
Run Code Online (Sandbox Code Playgroud)

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

  • 在实践中,任何与`__ne__`不一致的`__eq__`的类都会被打破. (26认同)
  • 请注意,'not x == y`还有一条指令不是*总是*true.当我把代码放入`if`时,结果发现它们都有相同数量的指令,只有一个有'POP_JUMP_IF_TRUE`而另一个有'POP_JUMP_IF_FALSE'(这是它们之间的唯一区别,除了使用不同的`COMPARE_OP`).当我编写没有`if`s的代码时,我得到了你得到的东西. (8认同)

Red*_*ift 29

@jonrsharpe对正在发生的事情有一个很好的解释.我想我只是在运行10,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)
Run Code Online (Sandbox Code Playgroud)

并且cProfile分析器结果如下:

在此输入图像描述

所以我们可以看到,if not x == 'val':和之间的差异很小,约为0.7%if x != 'val':.其中,if x != 'val':是最快的.

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

if x == 'val':
        pass
    else:
Run Code Online (Sandbox Code Playgroud)

实际上是最快的,并且if x != 'val':减少了~0.3%.这不是很易读,但我想如果你想要一个可以忽略不计的性能改进,那么可以沿着这条路走下去.

  • 我希望每个人都知道不要__这个信息!对0.3%的改进做出不可思议的改变 - 甚至改善10% - 很少是一个好主意,而且这种改进很可能是渐渐消失的(而不是[以一种好的方式](https:// www .youtube.com/watch?v = 5anLPw0Efmo):Python运行时的微小变化可以消除甚至逆转任何增益. (30认同)

Jed*_*one 6

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


kyl*_*e.a 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
Run Code Online (Sandbox Code Playgroud)

在这里你可以看到not x == y还有一个指令x != y.因此,除非您进行数百万次比较,否则在大多数情况下性能差异将非常小,即使这样也可能不会成为瓶颈的原因.


Jac*_*man 5

另外一个注释,因为其他答案大多正确地回答了你的问题,如果一个类只定义__eq__()而不是__ne__(),那么你的COMPARE_OP (!=)意志就会运行__eq__()并否定它.那时候,你的第三种选择可能会更有效率,但只有在你需要速度时才应考虑,因为很难快速理解.