Değilse Python == vs if! =


183

Bu iki kod satırı arasındaki fark nedir:

if not x == 'val':

ve

if x != 'val':

Biri diğerinden daha mı verimli?

Kullanmak daha iyi olur mu

if x == 'val':
    pass
else:

101
Ne kadar iyi okuyabilirseniz, programınızın darboğazının burada olacağından şüpheliyim
Thomas Ayoub

1
Bu soru beni "listede değil" ve "listede değil" durumunda ilgilendiriyor
SomethingSomething

5
@SomethingSomething onlar aynı şekilde yorumlanır.
jonrsharpe

4
Yukarıdaki yorumum için bir şey referansı: stackoverflow.com/q/8738388/3001761
jonrsharpe

1
@SomethingSomething olanlar için de aynı şey; sözdizimi bu şekilde yorumlanır, iki işlenenin ne olduğu önemli değildir.
jonrsharpe

Yanıtlar:


229

disİki sürüm için oluşturulan bayt koduna bakmak için kullanma :

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   

İkincisinin daha az operasyonu vardır ve bu nedenle biraz daha verimli olması muhtemeldir.


Bu işaret edildi commments içinde (teşekkür, @Quincunx sahip nerede) if foo != barvs if not foo == barişlem sayısı tam olarak aynı olduğunu, sadece bu var COMPARE_OPdeğişiklikler ve POP_JUMP_IF_TRUEgeçer 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

Bu durumda, her karşılaştırma için gereken iş miktarında bir fark olmadıkça, herhangi bir performans farkı görmeniz pek olası değildir.


Ancak, söz konusu nesnelerin uygulamalarına ve uygulamalarına bağlı olacağından , iki sürümün her zaman mantıksal olarak aynı olmayacağını unutmayın . Başına veri modeli belgelerine :__eq____ne__

Karşılaştırma işleçleri arasında herhangi bir zımni ilişki yoktur. Gerçeği bunun yanlış olduğu x==yanlamına gelmez x!=y.

Örneğin:

>>> class Dummy(object):
    def __eq__(self, other):
        return True
    def __ne__(self, other):
        return True


>>> not Dummy() == Dummy()
False
>>> Dummy() != Dummy()
True

Son olarak ve belki de en önemlisi: İki nereye, genel olarak şunlardır mantıksal olarak özdeş, x != yçok daha okunabilirnot x == y .


29
Uygulamada, __eq__tutarsız olan herhangi bir sınıf __ne__düz olarak kırılır.
Kevin

8
Lütfen bir talimat daha olması her zaman doğru değildir not x == y. Kodu bir koyduğumda, ifher ikisinin de aynı sayıda talimatı olduğu ortaya çıktı, sadece biri vardı POP_JUMP_IF_TRUEve diğeri POP_JUMP_IF_FALSE(farklı bir kullanım dışında, aralarındaki tek fark buydu COMPARE_OP). Kodu ifs olmadan derlediğimde, sahip olduğun şeyi aldım.
Justin

1
Karşılıklı ==ve !=birbirini dışlamayan başka bir örnek de nulldeğerleri içeren SQL benzeri bir uygulamadır . SQL nulldönmez trueiçin !=SQL arayüzlerinin piton uygulamaları da aynı sorunu olabilir bu yüzden başka bir değerle karşılaştırıldığında.
Joe

Keşke arasındaki olası farktan bahsetmemiş olsaydım not ==ve !=cevabımın en ilginç kısmı gibi görünüyor! Ben bunun neden, neden ve ne zaman mantıklı bir yer olduğunu sanmıyorum - bkz. Örneğin Python neden __ne__sadece bir operatör yöntemi var __eq__?
jonrsharpe

29

@jonrsharpe neler olup bittiğinin mükemmel bir açıklamasına sahiptir. 3 seçeneğin her birini 10.000.000 kez çalıştırırken zaman farkını göstereceğimi düşündüm (küçük bir farkın gösterilmesi için yeterli).

Kullanılan kod:

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)

Ve cProfile profil oluşturucu sonuçları:

resim açıklamasını buraya girin

Böylece if not x == 'val':ve arasında ~% 0.7 gibi çok küçük bir fark olduğunu görebiliyoruz if x != 'val':. Bunlardan if x != 'val':en hızlısı.

Ancak, en şaşırtıcı şekilde,

if x == 'val':
        pass
    else:

aslında en hızlı ve if x != 'val':~% 0.3 atıyor . Bu çok okunabilir değil, ama eğer ihmal edilebilir bir performans artışı isteseydiniz, biri bu rotadan aşağı gidebilir.


31
Umarım herkes bilmez bu bilgilere göre hareket ! % 0,3'lük bir iyileşme - hatta% 10'luk bir iyileşme için okunamayan değişiklikler yapmak nadiren iyi bir fikirdir ve bu tür bir iyileşmenin büyük olasılıkla kaybolması muhtemeldir (ve iyi bir şekilde değil : Python çalışma zamanında çok küçük değişiklikler) herhangi bir kazanç ortadan kaldırmak ve hatta tersine çevirebilecek.
Malvolio

1
@Malvolio Buna ek olarak, Python'un farklı uygulamaları .
Cees Timmerman

6

İlkinde Python, gerekenden daha fazla bir işlem yürütmek zorundadır (sadece eşit olmadığını kontrol etmek yerine, eşit olup olmadığını kontrol etmeli, dolayısıyla bir işlem daha yapmalıdır). Bir infazdan farkı söylemek imkansızdır, ancak birçok kez çalıştırılırsa ikincisi daha verimli olur. Genel olarak ikincisini kullanırdım, ama matematiksel olarak aynı


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

Burada not x == ybunun bir talimat daha olduğunu görebilirsiniz x != y. Milyonlarca karşılaştırma yapmadığınız sürece performans farkı çoğu durumda çok küçük olacaktır ve o zaman bile bu muhtemelen bir darboğazın nedeni olmayacaktır.


5

Diğer cevaplar çoğunlukla doğru sorunuza yanıt beri ek bir bilgi, bir sınıf yalnızca tanımlar eğer ki __eq__()değil __ne__(), daha sonra senin COMPARE_OP (!=)çalışacak __eq__()ve bunu inkâr. O zaman, üçüncü seçeneğiniz biraz daha verimli olacaktır, ancak sadece hıza İHTİYACINIZ varsa dikkate alınmalıdır, çünkü hızlı bir şekilde anlaşılması zordur.


3

Bu, onu okuma şeklinizle ilgilidir. notoperatörü dinamiktir, bu yüzden uygulayabilirsiniz

if not x == 'val':

Ancak !=, bir operatörün yaptığı şeyin tersini yapan daha iyi bir bağlamda okunabilir ==.


3
Ne demek " notoperatör dinamik" ?
jonrsharpe

1
@jonrsharpe Bence o "değil x" x .__ bool __ () [python 3 - python 2 nonzero kullanır ] diyecektir ve sonucu geri alacaktır (bkz. docs.python.org/3/reference/datamodel.html#object. __bool__ )
jdferreira

1

Yukarıdaki okunabilirlik yorumumu genişletmek istiyorum.

Yine, diğer (performans açısından önemsiz) endişeleri geçersiz kılan okunabilirliğe tamamen katılıyorum.

Belirtmek istediğim şey, beyin "pozitif" i "negatif" den daha hızlı yorumlar. Örneğin, "dur" ve "gitme" (sözcük sayısındaki farklılık nedeniyle oldukça berbat bir örnek).

Bu yüzden bir seçenek verildi:

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

işlevsel olarak eşdeğerliğe tercih edilir:

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

Daha az okunabilirlik / anlaşılabilirlik daha fazla hataya neden olur. Belki ilk kodlamada değil, (sizin kadar akıllı değil!) Bakım değişir ...


1
Beyin "pozitif" i "negatif" olandan daha hızlı yorumlar, bu deneyimden mi yoksa bu konudaki çalışmaları okudunuz mu? Sadece soruyorum çünkü koduna bağlı olarak (bunu yap) ya da (yap) bunu anlıyorum! = B daha kolay.
lafferc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.