Python if not==vs if=

Python if not==vs if=,python,if-statement,equality,Python,If Statement,Equality,这两行代码之间的区别是什么: if not x == 'val': 及 一个比另一个更有效率吗 使用它会更好吗 if x == 'val': pass else: 在第一种情况下,Python必须执行一个超出必要范围的操作(而不是只检查not equal to,它必须检查它是否等于true,从而再执行一个操作)。不可能区分一次执行与另一次执行的区别,但如果多次运行,第二次执行将更有效。总的来说,我会使用第二个版本,但从数学上讲,它们是相同的,用于查看为两个版本生成的字节码: 非==

这两行代码之间的区别是什么:

if not x == 'val':

一个比另一个更有效率吗

使用它会更好吗

if x == 'val':
    pass
else:

在第一种情况下,Python必须执行一个超出必要范围的操作(而不是只检查not equal to,它必须检查它是否等于true,从而再执行一个操作)。不可能区分一次执行与另一次执行的区别,但如果多次运行,第二次执行将更有效。总的来说,我会使用第二个版本,但从数学上讲,它们是相同的,用于查看为两个版本生成的字节码:

非==

  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   
  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 POP_JUMP_IF_FALSE       16
=

  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   
  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 POP_JUMP_IF_FALSE       16
后者的业务较少,因此可能会稍微更有效率


有人指出(谢谢,)如果foo!=bar
if not foo==bar
操作数完全相同,只是
比较OP
发生了变化,并且
POP_JUMP_if_TRUE
切换到
POP_JUMP_if_FALSE

非==

  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_TRUE        16
=

  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   
  2           0 LOAD_FAST                0 (foo)
              3 LOAD_FAST                1 (bar)
              6 COMPARE_OP               3 (!=)
              9 POP_JUMP_IF_FALSE       16
在这种情况下,除非每次比较所需的工作量有所不同,否则您不太可能看到任何性能差异


但是,请注意,这两个版本的在逻辑上并不总是相同的,因为它将取决于所讨论对象的
\uuuuuu eq\uuuu
的实现。Per:

比较运算符之间没有隐含的关系。这个
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
比x==y
可读性强得多

>>> 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

在这里,您可以看到
notx==y
x!=y
。因此,在大多数情况下,性能差异将非常小,除非您进行数百万次比较,即使这样,这也不可能成为瓶颈的原因

这是关于你的阅读方式
not
运算符是动态的,这就是为什么您可以在中应用它

if not x == 'val':

但是
=
可以在更好的上下文中被理解为一个运算符,它的作用与
==
相反。

@Jornsharpe对发生的事情有很好的解释。我想我应该在运行3个选项10000000次时显示时间上的差异(足以显示细微的差异)

使用的代码:

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 profiler结果:

因此,我们可以看到,
如果不是x='val':
如果x!='val':
。其中,
如果x!='val':
是最快的。 然而,最令人惊讶的是,我们可以看到

if x == 'val':
        pass
    else:

实际上是最快的,如果x!='val':
0.3%。这不是很容易理解,但我想如果你想要一个微不足道的性能改进,你可以走这条路。

另一个注意事项,因为其他答案基本上正确地回答了你的问题,那就是如果一个类只定义
\uuuuuuueq\uuuo()
而不是
\une\uuu()
,那么你的
比较操作(!=)
将运行
\uuuu eq\uuu()
并对其求反。此时,您的第三个选项可能会稍微高效一些,但只有在您需要速度的情况下才应该考虑,因为它很难快速理解。

我想进一步阐述我上面的可读性评论

同样,我完全同意可读性凌驾于其他(性能无关紧要的)考虑之上

我想指出的是,大脑对“积极”的理解快于对“消极”的理解。例如,“停止”与“不要走”(由于字数不同,这是一个相当糟糕的例子)

因此,我们有一个选择:

if a == b
    (do this)
else
    (do that)
比功能上等效的更可取:

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

可读性/可理解性较差会导致更多错误。也许不是在初始编码中,但是(没有你那么聪明!)维护更改了…

你能读到的越好,我怀疑你的程序的瓶颈会在这里。这个问题让我对“不在列表中的x”和“不在列表中的x”感兴趣 case@SomethingSomething它们的解释是相同的。@SomethingSomething我的上述评论的参考:@SomethingSomething这些也一样;语法是如何解释的,这与两个操作数是什么无关。你说“
运算符是动态的”是什么意思?@jornsharpe我想他的意思是“not x”将调用x._ubool__;(),任何与
不一致的
\uuuu eq\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。当我把代码放入一个
if
,结果发现它们都有相同数量的指令,只有一条指令是
POP\u JUMP\u if\u TRUE
,另一条指令是
POP\u JUMP\u if\u FALSE
(这是它们之间唯一的区别,除了使用不同的
比较\u OP
)。当我编译没有
if
的代码时,我得到了您得到的。另一个例子是
==
=
不是互斥的,它是一个类似SQL的实现,涉及
null
值。在SQL
null
中,不会将
true
返回到
=not===
之间可能存在的差异=,这似乎是我答案中最有趣的部分!我不认为这是一个值得深思的地方,如果、为什么和什么时候这样做是有意义的——例如,我希望每个人都不知道