Neden '==' veya 'is' kullanarak dizeleri karşılaştırmak bazen farklı bir sonuç doğurur?


1146

İki değişkenin değerine ayarlandığı bir Python programım var 'public'. Koşullu bir ifadede var1 is var2başarısız olan karşılaştırmaya sahibim, ancak bunu değiştirirsem var1 == var2geri döner True.

Şimdi Python yorumcumu açar ve aynı "is" karşılaştırmasını yaparsam başarılı olur.

>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True

Burada ne eksik?



3
Eğer bir konsol girişi aracılığıyla örneğin okurken da bu sorun oluşur: input = raw_input("Decide (y/n): "). Bu durumda bir "y" girdisi ve if input == 'y':"True" if input is 'y':döndürürken False değerini döndürür.
Semjon Mössinger

4
Bu blog, herhangi bir cevaptan çok daha eksiksiz bir açıklama sağlar guilload.com/python-string-interning
Chris_Rands

1
@ Chris-
rico'dan

Yanıtlar:


1533

iskimlik testi, ==eşitlik testidir. kodunuzda neler olduğu yorumlayıcıda şöyle taklit edilir:

>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False

yani, aynı olmadıklarına şaşmamalı, değil mi?

Başka bir deyişle: isbirid(a) == id(b)


17
ahh eq ile aynı mı? eşit mi? şemada, anladım.
jottos

47
Veya Java'da ==vs. .equals()En iyi yanı, Python'un ==Java'ya benzememesidir ==.
MatrixFrog

11
@ Крайст: sadece tek bir Nonedeğer var. Yani her zaman aynı kimliğe sahip.
SilentGhost

18
Bu OP'nin "is -> True" örneğini ele almaz.
user2864740

6
@AlexanderSupertramp, dize stajı nedeniyle .
Chris Rico

570

: Burada Diğer cevaplar doğru iskullanılan kimlik ederken, karşılaştırma ==için kullanılan eşitlik karşılaştırılması. Önem verdiğiniz şey eşitlik olduğundan (iki karakter aynı karakterleri içermelidir), bu durumda isoperatör basitçe yanlıştır ve ==bunun yerine kullanmanız gerekir .

isEtkileşimli çalışmanın nedeni , varsayılan olarak (çoğu) dize değişmezinin stajyer olmasıdır . Wikipedia'dan:

Stajlı dizeler, dize karşılaştırmalarını hızlandırır; bu, bazen dize anahtarları içeren karma tablolara dayanan uygulamalarda (derleyiciler ve dinamik programlama dili çalışma zamanları gibi) bir performans darboğazıdır. Staj yapmadan, iki farklı dizenin eşit olup olmadığını kontrol etmek, her iki dizenin her karakterini incelemeyi içerir. Bu birkaç nedenden dolayı yavaştır: doğal olarak dizelerin uzunluğundaki O (n); tipik olarak zaman alan hafızanın çeşitli bölgelerinden okumalar gerektirir; ve okumalar işlemci önbelleğini doldurur, yani diğer ihtiyaçlar için daha az önbellek vardır. Stajyer dizelerle, orijinal stajyer işleminden sonra basit bir nesne kimlik testi yeterlidir; bu tipik olarak işaretçi eşitlik testi olarak uygulanır,

Bu nedenle, programınızda aynı değere sahip iki dize değişmezine (tam anlamıyla program kaynak kodunuza yazılan, tırnak işaretleri ile çevrili kelimeler) sahip olduğunuzda, Python derleyicisi dizeleri otomatik olarak stajyerleştirerek her ikisini de aynı şekilde depolar bellek konumu. (Bunun her zaman gerçekleşmediğini ve bunun ne zaman gerçekleşeceğine ilişkin kuralların oldukça kıvrımlı olduğunu unutmayın, bu yüzden lütfen üretim kodundaki bu davranışa güvenmeyin!)

Etkileşimli oturumunuzda her iki dize de aslında aynı bellek konumunda saklandığından, aynı kimliğe sahiptirler , böylece isoperatör beklendiği gibi çalışır. Ancak bir dizeyi başka bir yöntemle oluşturursanız (bu dize tam olarak aynı karakterleri içeriyor olsa bile ), dize eşit olabilir , ancak aynı dize değildir - yani, farklı bir kimliğe sahiptir , çünkü bellekte farklı bir yerde saklanır.


6
Dizeler stajyer olduğunda kıvrımlı kurallar hakkında daha fazla bilgiyi nerede okuyabilirim?
Noctis Skytower

89
Ayrıntılı bir açıklama için +1. GERÇEKTEN ne olduğunu açıklamadan diğer cevabın bu kadar çok oy aldığından emin değilim.
That1Guy

4
soruyu okuduğumda tam olarak bunu düşündüm. Kabul edilen cevap kısadır ancak gerçeği içerir, ancak bu cevap işleri daha iyi açıklar . Güzel!
Sнаđошƒаӽ

3
@NoctisSkytower Aynı Googled ve bu bulundu guilload.com/python-string-interning
xtreak

5
@ naught101: Hayır, kural, ne tür bir kontrol istediğinizi seçmek ==ve arasında seçim yapmaktır is. Dizelerin eşit olmasını (yani, aynı içeriğe sahip olmak) önemsiyorsanız , her zaman kullanmalısınız ==. Herhangi iki Python adının aynı nesne örneğine atıfta bulunup bulunmadığına önem veriyorsanız, kullanmalısınız is. Sen gerekebilir isde içerikleri hakkında bakmakta olmadan farklı değerlerin kolları sürü, ya da başka bir şeyden sadece bir tane olduğunu biliyorsanız ve o şey gibi davranarak diğer nesneleri göz ardı etmek istiyorum ki eğer sen yazma kodu. Emin değilseniz, her zaman seçin ==.
Daniel Pryden

108

isİse anahtar nesnesi kimliği için bir test ==bir değer karşılaştırmasıdır.

Kullanırsanız is, sonuç yalnızca nesne aynı nesne ise doğru olur. Ancak, ==nesnenin değerleri aynı olduğunda doğru olacaktır.


57

Dikkat edilmesi gereken son bir şey sys.intern, aynı dizeye başvuru aldığınızdan emin olmak için işlevi kullanabilirsiniz :

>>> from sys import intern
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

Yukarıda belirtildiği gibi, isdizelerin eşitliğini belirlemek için kullanmamalısınız . Ancak bu, bir tür garip gereksiniminiz olup olmadığını bilmek için yardımcı olabilir is.

Bu Not internfonksiyonu Python 2 üzerinde yerleşik olarak kullanılan ama taşındı sysPython 3 modülü.


43

iskimlik testi, ==eşitlik testidir. Bunun anlamı, isiki şeyin aynı veya sadece eşdeğer olup olmadığını kontrol etmenin bir yoludur .

Diyelim ki basit bir personnesneniz var. Eğer 'Jack' olarak isimlendirilirse ve '23' yaşındaysa, 23 yaşındaki başka bir Jack'e eşdeğer, ama aynı kişi değil.

class Person(object):
   def __init__(self, name, age):
       self.name = name
       self.age = age

   def __eq__(self, other):
       return self.name == other.name and self.age == other.age

jack1 = Person('Jack', 23)
jack2 = Person('Jack', 23)

jack1 == jack2 #True
jack1 is jack2 #False

Aynı yaştalar, ama aynı insan örneği değiller. Bir dize diğerine eşdeğer olabilir, ancak aynı nesne değildir.


Kümeyi değiştirirseniz jack1.age = 99, bu değişmez jack2.age. Çünkü iki farklı örnek, öyle jack1 is not jack2. Ancak, jack1 == jack2adları ve yaşları aynıysa birbirlerine eşit olabilirler . Dizeler için daha karmaşık hale gelir, çünkü dizeler Python'da değişmezdir ve Python genellikle aynı örneği yeniden kullanır. Özel durumları (dizeleri) değil, basit vakaları (normal bir nesne) kullandığından bu açıklamayı seviyorum.
Flimm


28

Ne yaptığınızdan emin değilseniz, '==' kullanın. Bu konuda biraz daha bilginiz varsa, 'Hiçbiri' gibi bilinen nesneler için 'is' kullanabilirsiniz.

Aksi takdirde, işlerin neden çalışmadığını ve bunun neden olduğunu merak edersiniz:

>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False

Bazı şeylerin farklı python sürümleri / uygulamaları arasında aynı kalması garanti edilip edilmediğinden bile emin değilim.


1
Ints'i yeniden atamanın bu durumu nasıl tetiklediğini gösteren ilginç bir örnek. Bu neden başarısız oldu? Stajyerlik veya başka bir şey yüzünden mi?
Paul

Tercümanın uygulanması nedeniyle yanlış döndürülmesinin nedeni gibi görünüyor: stackoverflow.com/questions/132988/…
Paul


@ArchitJain Evet, bu bağlantılar oldukça iyi açıklıyor. Onları okuduğunuzda, hangi sayıları kullanabileceğinizi bilirsiniz. Keşke bunun neden hala iyi bir fikir olmadığını açıklamak istiyorlardı :) Bunun, herkesin de yaptığını varsaymanın iyi bir fikir olmadığını biliyorsunuz (veya dahili numara aralığının asla değişmeyeceğini)
Mattias Nilsson

20

Python ile olan sınırlı deneyimimden, isiki nesneyi aynı değere sahip iki farklı nesnenin aksine aynı nesne olup olmadığını görmek için karşılaştırmak için kullanılır. ==değerlerin aynı olup olmadığını belirlemek için kullanılır.

İşte iyi bir örnek:

>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True

s1unicode bir dizedir ve s2normal bir dizedir. Aynı tipte değil, aynı değerde.


17

Bence 'is' karşılaştırması yanlış olarak değerlendirildiğinde, iki farklı nesnenin kullanılması gerçeğiyle ilgilidir. Doğru olarak değerlendirilirse, bu, dahili olarak aynı nesneyi kullanması ve yeni bir nesne oluşturmadığı anlamına gelir, muhtemelen bunları 2 saniye kadar bir süre içinde oluşturduğunuzdan ve optimize edilmiş ve aralarında büyük bir zaman boşluğu olmadığından aynı nesneyi kullanır.

Eğer eşitlik operatörünü kullanarak edilmelidir nedeni budur ==, değil isbir dize nesnenin değerini karşılaştırmak.

>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>> 

Bu örnekte, daha önce 'one' değerine eşit farklı bir dize nesnesi olan s2'yi yaptım, ancak syorumlayıcı başlangıçta 'one' a atamadığımla aynı nesneyi kullanmadığı için aynı nesne değil, eğer bu olsaydı onları aynı nesne haline getirirdi.


3
.replace()Bu bağlamda örnek olarak kullanmak muhtemelen en iyisi değildir, çünkü semantiği kafa karıştırıcı olabilir. s2 = s2.replace()her zaman yeni bir dize nesnesi oluşturur, yeni dize nesnesini atar s2ve sonra s2kullanılan dize nesnesini atar . Öyle olsa bile, s = s.replace('one', 'one')yeni bir dize nesnesi elde edersiniz.
Daniel Pryden

13

Bunun "stajyer" dizeler olarak bilindiğine inanıyorum. Python bunu yapar, Java da yapar ve optimize edilmiş modlarda derlenirken C ve C ++ da yapar.

İki özdeş dize kullanırsanız, iki dize nesnesi oluşturarak belleği boşa harcamak yerine, aynı içeriğe sahip tüm iç içe dizeler aynı belleği gösterir.

Aynı içeriğe sahip iki dize aynı dize nesnesini işaret ettiğinden, bu, Python "işlevinin" True döndürdüğü "sonucunu verir. Bu, Java ve C'de de olacaktır.

Bu sadece bellek tasarrufu için kullanışlıdır. Dize eşitliğini test etmek için ona güvenemezsiniz, çünkü çeşitli tercümanlar ve derleyiciler ve JIT motorları her zaman bunu yapamaz.


12

Soru eski olmasına rağmen soruyu cevaplıyorum çünkü yukarıdaki cevaplar dil referansını alıntılamıyor

Aslında is operatörü kimliği kontrol eder ve == operatör eşitliği kontrol eder,

Dil Referansından:

Türler, nesne davranışının neredeyse tüm yönlerini etkiler. Nesne kimliğinin önemi bile bir anlamda etkilenir: değişmez türler için, yeni değerleri hesaplayan işlemler aslında aynı tür ve değere sahip mevcut herhangi bir nesneye bir referans döndürebilirken, değiştirilebilir nesneler için buna izin verilmez . Örneğin, a = l'den sonra; b = 1, a ve b, uygulamaya bağlı olarak bir değere sahip aynı nesneyi gösterebilir veya göstermeyebilir, ancak c = [] sonrasında; d = [], c ve d'nin iki farklı, benzersiz, yeni oluşturulmuş boş listeyi ifade ettiği garanti edilir. (C = d = [] öğesinin aynı nesneyi hem c hem de d'ye atadığını unutmayın.)

bu yüzden yukarıdaki ifadeden değişmez bir tür olan dizelerin "is" ile işaretlendiğinde başarısız olabileceğini ve "is" ile işaretlendiğinde başarılı olabileceğini belirtebiliriz

Aynısı, aynı zamanda değişmez tip olan int, tuple için de geçerlidir.


8

==Operatör test değeri eşdeğerlik. isOperatör testleri nesne kimliği, iki olsun Python testler gerçekten aynı nesne (bellekte aynı adreste yani canlı) bulunmaktadır.

>>> a = 'banana'
>>> b = 'banana'
>>> a is b 
True

Bu örnekte, Python sadece ve her ikisi de tek bir dize nesnesini oluşturan ave bbuna karşılık gelir. Bunun nedeni, Python'un bazı dizeleri dahili olarak önbelleğe alması ve bir optimizasyon olarak yeniden kullanmasıdır. Normal davranışı tetiklemek için daha uzun dizeler kullanmanız gerekir:

>>> a = 'a longer banana'
>>> b = 'a longer banana'
>>> a == b, a is b
(True, False)

İki liste oluşturduğunuzda, iki nesne elde edersiniz:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False

Bu durumda, iki listenin eşdeğer olduğunu söyleyebiliriz, çünkü aynı öğelere sahiptirler, ancak aynı değildirler, çünkü aynı nesne değildirler. İki nesne özdeş ise, aynı zamanda eşdeğerdirler, ancak eşdeğerlerse mutlaka aynı değildirler.

Bir anesneye atıfta bulunursanız ve atarsanız b = a, her iki değişken de aynı nesneye başvurur:

>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True

7

isbellek konumunu karşılaştıracaktır. Nesne düzeyinde karşılaştırma için kullanılır.

==Programdaki değişkenleri karşılaştıracaktır. Bir değer düzeyinde kontrol için kullanılır.

is adres seviyesi denkliğini kontrol eder

== değer seviyesi denkliğini kontrol eder


3

iskimlik testi, ==eşitlik testi (bkz. Python Belgeleri) ).

Çoğu durumda, eğer a is böyleyse a == b. Ancak istisnalar var, örneğin:

>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False

Yani, sadece iskimlik testleri için kullanabilirsiniz , asla eşitlik testleri için kullanamazsınız .

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.