Python! = "Vs değil" işlemi


250

Yorumunda bu soruya , benim kullandığım önerilen bir bildiri gördü

result is not None

vs

result != None

Farkın ne olduğunu ve neden birinin diğerine önerilebileceğini merak ediyordum?



1
Hmm. Her iki soruya da cevap aynı kavram olsa da, buradaki yukarı ve ayrıntılı cevapların kimlik ve eşitlik testi kavramına bağımsız olarak katkıda bulunduğunu düşünüyorum.
viksit

Yanıtlar:


301

==Bir olan eşitlik testi . Sağ tarafın ve sol tarafın eşit nesneler olup olmadığını kontrol eder ( __eq__veya __cmp__yöntemlerine göre ).

isbir kimlik testidir . Sağ taraf ile sol tarafın aynı nesne olup olmadığını kontrol eder. Hiçbir yöntem çağrısı yapılmaz, nesneler isişlemi etkileyemez .

Gibi davranmak isteyebileceğiniz veya kıyaslandığında kırılan nesnelere karşı korumak istediğiniz nesneler hakkında umursamadığınız tektonlar için is(ve is not) kullanırsınız .NoneNoneNone


3
Cevabınız için teşekkürler - Bir nesnenin kırılabileceği durumları Yok ile karşılaştırır mısınız?
viksit

3
@viksit. Nonebirkaç yöntemi vardır ve neredeyse hiç özniteliği yoktur. Senin Eğer __eq__deney yöntemi veya niteliği beklenen, bu bozabilir. def __eq__( self, other ): return self.size == other.size. Örneğin, eğer otherolursa kırılacaktır None.
S.Lott

36
Bunu idrak etmesini sevdiğim yoludur: Python en isJava'nın gibidir ==. Python'lar ==Java gibidir .equals(). Tabii ki bu sadece Java'yı biliyorsanız yardımcı olur.
MatrixFrog

4
@MatrixFrog: In PHP veya JavaScript biz söyleyebilirim isgibidir ===(çok eşit) ve tersine is notgibidir !==(tam olarak eşit değildir).
Orwellophile

3
is notTek bir operatör mü yoksa sadece isdahili gibi bir sonucu not foo is barmu olumsuz etkiliyor ?
Asad Moosvi

150

İlk olarak, birkaç terimi gözden geçirmeme izin verin. Sorunuzun yanıtlanmasını istiyorsanız, "Sorunuzu cevaplama" bölümüne gidin.

Tanımlar

Nesne kimliği : Bir nesne oluşturduğunuzda, nesneyi bir değişkene atayabilirsiniz. Daha sonra başka bir değişkene de atayabilirsiniz. Ve başka.

>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True

Bu durumda, cancel, closeve dismisstüm bellekte aynı nesneyi. Yalnızca bir Buttonnesne oluşturdunuz ve her üç değişken de bu nesneyi ifade ediyor. Biz demek cancel, closeve dismisstüm atıfta özdeş nesneler; yani, tek bir nesneye atıfta bulunurlar.

Nesne eşitliği : İki nesneyi karşılaştırdığınızda, genellikle bellekteki tam olarak aynı nesneyi ifade ettiğini umursamazsınız . Nesne eşitliği ile iki nesnenin karşılaştırması için kendi kurallarınızı tanımlayabilirsiniz. Yazarken if a == b:, aslında diyorsun if a.__eq__(b):. Bu , kendi karşılaştırma mantığınızı kullanabilmeniz için __eq__üzerinde bir yöntem tanımlamanızı sağlar a.

Eşitlik karşılaştırmaları için gerekçe

Gerekçe: İki nesne aynı verilere sahiptir, ancak aynı değildir. (Bellekteki aynı nesne değildirler.) Örnek: Dizeler

>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True

Not: Burada unicode dizeleri kullanıyorum, çünkü Python bellekte yenilerini oluşturmadan normal dizeleri yeniden kullanmak için yeterince akıllı.

Burada, iki unicode dizgim var ave b. Aynı içeriğe sahipler, ancak bellekteki aynı nesne değiller. Ancak, onları karşılaştırdığımızda, onların eşit karşılaştırmasını istiyoruz. Burada olan, unicode nesnesinin __eq__yöntemi uyguladığıdır .

class unicode(object):
    # ...

    def __eq__(self, other):
        if len(self) != len(other):
            return False

        for i, j in zip(self, other):
            if i != j:
                return False

        return True

Not: __eq__on unicodekesinlikle bundan daha verimli bir şekilde uygulanır.

Gerekçe: İki nesnenin verileri farklıdır, ancak bazı önemli veriler aynı ise aynı nesne olarak kabul edilir. Örnek: Çoğu model verisi türü

>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True

Burada iki Dell monitörüm var ave b. Aynı marka ve modele sahiptirler. Bununla birlikte, ne aynı verilere sahiptir ne de bellekteki aynı nesnedir. Ancak, onları karşılaştırdığımızda, onların eşit karşılaştırmasını istiyoruz. Burada olan şey, Monitor nesnesinin __eq__yöntemi uygulamasıdır .

class Monitor(object):
    # ...

    def __eq__(self, other):
        return self.make == other.make and self.model == other.model

Sorunuzu cevaplama

Karşılaştırırken None, daima kullanın is not. Python'da hiçbiri bir singleton değildir - bellekte sadece bir örneği vardır.

Kimlik karşılaştırılarak , bu çok hızlı bir şekilde gerçekleştirilebilir. Python, başvurduğunuz nesnenin global None nesnesiyle aynı bellek adresine sahip olup olmadığını kontrol eder - iki sayının çok, çok hızlı bir karşılaştırması.

Eşitliği karşılaştırarak Python, nesnenizin bir __eq__yöntemi olup olmadığını aramalıdır . Değilse, bir __eq__yöntem arayan her bir üst sınıfı inceler . Birini bulursa, Python onu arar. Bu, özellikle __eq__yöntem yavaşsa ve diğer nesnenin olduğunu fark ettiğinde hemen geri dönmezse kötüdür None.

Uygulamadınız __eq__mı? Daha sonra Python muhtemelen __eq__yöntemi bulacaktır objectve bunun yerine kullanacaktır - ki bu zaten nesne kimliğini kontrol eder.

Python'daki diğer birçok şeyi karşılaştırırken, kullanacaksınız !=.


42

Aşağıdakileri göz önünde bulundur:

class Bad(object):
    def __eq__(self, other):
        return True

c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)

1
Bu çok yardımcı ve basit bir örnektir. Teşekkür ederim.
msarafzadeh

18

Nonetek bir nesnedir, bu nedenle kimlik karşılaştırması her zaman işe yarayacaktır, oysa bir nesne eşitlik karşılaştırmasını taklit edebilir .__eq__().


Ah ilginç! Hangi durumlarda eşitlik karşılaştırmasını sahte yapmak isteyebilirsiniz? Bunun bir şekilde güvenlikle ilgili sonuçları olduğunu tahmin ediyorum.
viksit

1
Eşitliği taklit etmekle değil, eşitliği uygulamakla ilgili . Bir nesnenin diğeriyle nasıl karşılaştırılacağını tanımlamak için birçok neden vardır.
Thomas Wouters

1
Güvenlik çıkarımlarından daha karışıklık çıkarımları olduğunu söyleyebilirim .
Greg Hewgill

2
Eşitliğe karşı sahte bir nedene karşı gelmedim None, ancak Nonediğer türlere karşı eşitliğin uygulanmasının bir yan etkisi olarak yanlış davranışlar ortaya çıkabilir. Sadece doğruluk sonuçları olduğu için çok fazla güvenlik etkisi değil.
Ignacio Vazquez-Abrams

Ah bu taraftan anlıyorum. Açıklama için teşekkürler.
viksit

10
>>> () ()
Doğru
>>> 1 1'dir
Doğru
>>> (1,) == (1,)
Doğru
>>> (1,) (1,)
Yanlış
>>> a = (1,)
>>> b = a
>>> a b'dir
Doğru

Bazı nesneler tek tonludur ve bu nedenle isonlarla eşdeğerdir ==. Çoğu değil.


4
Bunların çoğu sadece tesadüf / uygulama ayrıntılarıyla çalışır. ()ve 1doğal olarak tekil değildir.
Mike Graham

1
CPython uygulamasında küçük tamsayılar ( -NSMALLNEGINTS <= n <= NSMALLPOSINTS) ve boş küpe olan singletons. Aslında belgelenmemiş ve garanti edilmemiştir, ancak değişmesi olası değildir.
ephemient

3
Bu nasıl uygulanır, ancak anlamlı, yararlı veya eğitici değildir.
Mike Graham

1
Ve özellikle, CPython tek Python uygulaması değildir. Python uygulamaları arasında değişiklik gösterebilen davranışlara güvenmek benim için genellikle bir Bad Idea ™ gibi görünmektedir.
me_and
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.