Python if not = = vs if!=

в чем разница между этими двумя строками кода:

if not x == 'val':

и

if x != 'val':

является ли один более эффективным, чем другой?

лучше использовать

if x == 'val':
    pass
else:

7 ответов


используя 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   

последний имеет меньше операций, и поэтому, вероятно, будет немного более эффективным.


было указано в commments (спасибо, @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

наконец, и пожалуй самое главное: в общем, где два are логически идентичные, x != y гораздо более читабельно, чем not x == y.


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

enter image description here

таким образом, мы можем видеть, что существует очень незначительная разница ~0.7% между if not x == 'val': и if x != 'val':. Из них if x != 'val': - это самый быстрый.

однако, что самое удивительное, мы видим, что

if x == 'val':
        pass
    else:

на самом деле самый быстрый, и бьет if x != 'val': на ~0.3%. Это не очень читаемо, но я думаю, если вы хотите незначительное улучшение производительности, можно пойти по этому пути.


в первом 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. Таким образом, разница в производительности будет очень мала в большинстве случаев, если вы не делаете миллионы сравнений, и даже тогда это, вероятно, не будет причиной узкого места.


дополнительное Примечание, так как другие ответы ответили на ваш вопрос в основном правильно, заключается в том, что если класс определяет только __eq__(), а не __ne__(), тогда как COMPARE_OP (!=) будет работать __eq__() и отменяет его. В то время ваш третий вариант, вероятно, будет немного более эффективным, но его следует рассматривать только в том случае, если вам нужна скорость, так как это трудно понять быстро.


речь идет о вашем способе чтения. not оператор динамический, поэтому вы можете применить его в

if not x == 'val':

но != можно было бы прочитать в лучшем контексте как оператор, который делает противоположное тому, что == делает.


Я хочу расширить свой комментарий читаемости выше.

опять же, я полностью согласен с читаемостью, переопределяющей другие (незначительные по производительности) проблемы.

Итак, выбор:

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

предпочтительнее функционально эквивалентны:

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

меньшая читаемость / понятность приводит к большему количеству ошибок. Возможно, не в начальном кодировании, но (не так умно, как вы!) изменения содержания...