Python'un "eşittir" operatörünü anlama


110

isOperatör değişkenlerin değerlerini fakat örneklerini kendileri uymuyor.

Gerçekten ne anlama geliyor?

Adlandırılmış xve yher iki değişkende aynı değerleri atayan iki değişken bildirdim , ancak isişleci kullandığımda yanlış döndürüyor .

Bir açıklamaya ihtiyacım var. İşte kodum.

x = [1, 2, 3]
y = [1, 2, 3]

print(x is y)  # It prints false!

Yanıtlar:


181

isOperatörün neyi test ettiğini yanlış anladınız. İki değişkenin aynı değere sahip olup olmadığını değil, iki değişkenin aynı nesneyi gösterip göstermediğini test eder .

isOperatörün belgelerinden :

Operatörler isve is notnesne kimliği için testi: x is yancak ve ancak bu durum geçerlidir xve yaynı nesne bulunmaktadır.

Kullanım ==yerine operatörü:

print(x == y)

Bu baskı True. xve yiki ayrı listedir:

x[0] = 4
print(y)  # prints [1, 2, 3]
print(x == y)   # prints False

id()İşlevi kullanırsanız, bunu görürsünüz xve yfarklı tanımlayıcılara sahip olursunuz :

>>> id(x)
4401064560
>>> id(y)
4401098192

ama atayacak olursanız yiçin xaynı nesneye her iki noktada:

>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True

ve isher ikisinin de aynı nesne olduğunu gösterir, geri döner True.

Python'da isimlerin sadece değerleri referans alan etiketler olduğunu unutmayın ; aynı nesneyi gösteren birden çok adınız olabilir. isiki ismin aynı nesneyi işaret edip etmediğini size söyler. ==iki adın aynı değere sahip nesnelere atıfta bulunup bulunmadığını size söyler.


13
Yani A is Baynıdır id(A) == id(B).
imallett

2
@imallett: Bu id(A), bir değişkende saklamamanız ve daha sonra variable == id(B)hala çalışmayı beklemeniz koşuluyla aynı test için bir proxy'dir ; Abu arada silinmiş olsaydı Baynı hafıza konumu verilmiş olabilirdi.
Martijn Pieters

1
Yorumlarda biçimlendirilemedi. Ama ilginç bir şey var. :) >>> x = 5 \n>>> y = 5 \n>>> x is y \nTrue \n>>> x == y \nTrue \n>>>\n
Haranadh

5
Küçük tam sayılar, çok sık kullanıldıkları için CPython'da tutulur. Bu bir optimizasyon. x = 5; y = 5; x, y => Doğru çünkü id (x) == id (y). Yeniden kullanılan aynı tamsayı nesnesidir. Tam sayılar değişmez olduğu için Python'da çalışır. X = 1.0 yaparsanız; y = 1.0 veya x = 9999; y = 9999, aynı özdeşlik olmayacak çünkü kayan değerler ve daha büyük inçler dahil edilmemiştir.
Magnus lycka

1
@ MagnusLyckå, değişmez nesnelerin önbelleğe alınmasına neden olabilecek başka optimizasyonlar da vardır. Örneğin, örneğinizi yeni bir işlevde veya etkileşimli yorumlayıcıda ayırıcı bir noktalı virgülle birlikte çalıştırırsanız, onların da aynı kimliğe sahip olduğunu görürsünüz.
Martijn Pieters

60

Başka bir kopya , iki eşit dizgenin genel olarak neden aynı olmadığını soruyordu, bu da burada gerçekten cevaplanmıyor:

>>> x = 'a' 
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False

Peki neden aynı dizge değiller? Özellikle bu göz önüne alındığında:

>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True

İkinci bölümü biraz erteleyelim. İlki nasıl doğru olabilir?

Yorumlayıcının bir "interning tablosu", yani dizgi değerlerini dizgi nesnelerine eşleyen bir tablo olması gerekir, böylece içerikle her yeni bir dizgi oluşturmaya çalıştığınızda 'abc', aynı nesneyi geri alırsınız. Wikipedia'da staj yapmanın nasıl çalıştığına dair daha ayrıntılı bir tartışma var.

Ve Python vardır tabloyu interning bir dize; sys.internyöntemle dizeleri manuel olarak interneti yapabilirsiniz .

Aslında, Python'un herhangi bir değişmez türü otomatik olarak staj yapmasına izin verilir , ancak bunu yapması zorunlu değildir . Farklı uygulamalar, farklı değerler içerecektir.

CPython (hangi uygulamayı kullandığınızı bilmiyorsanız, kullandığınız uygulama) otomatik olarak küçük tamsayılar ve bazı özel tekler gibi Falsedizeler (veya büyük tam sayılar veya küçük tupllar veya başka herhangi bir şey) değil. Bunu oldukça kolay görebilirsiniz:

>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False

Tamam, ama neden olduğunu zve waynı?

Bu otomatik olarak yorumlayıcı değil, derleyici katlama değerleri.

Aynı derleme zamanı dize (aynı modülde iki kez görünürse tam olarak ne bu araçlar, çünkü bir dize ile aynı şey değil o tanımlamak zordur r'abc', 'abc've 'a' 'b' 'c'anlaşılması kolay tüm farklı değişmezleri ama aynı dize ancak sezgisel olarak), derleyici iki referansla dizenin yalnızca bir örneğini oluşturur.

Aslında, derleyici daha da ileri gidebilir: optimizer tarafından 'ab' + 'c'dönüştürülebilir 'abc', bu durumda 'abc'aynı modülde bir sabitle birlikte katlanabilir .

Yine, bu Python'a izin verilen ancak yapılması zorunlu olmayan bir şeydir. Ancak bu durumda, CPython her zaman küçük dizeleri (ve ayrıca, örneğin, küçük dizeleri) katlar. (Etkileşimli yorumlayıcının ifade-bazında derleyici, tek seferde modül derleyici ile aynı optimizasyonu çalıştırmasa da, tam olarak aynı sonuçları etkileşimli olarak görmezsiniz.)


Peki bir programcı olarak bu konuda ne yapmalısınız?

Şey ... hiçbir şey. İki değişmez değerin aynı olup olmadığını umursamak için neredeyse hiçbir nedeniniz yoktur. a is bBunun yerine ne zaman kullanabileceğinizi bilmek istiyorsanız a == b, yanlış soruyu soruyorsunuz. a == bİki durum dışında her zaman kullanın :

  • Tekil değerlerle daha okunaklı karşılaştırmalar için x is None.
  • Bilmeniz gereken zaman değişken değerleri için değişen yapısıyla olmadığını xetkileyecektir y.

1
Mükemmel bir açıklama, özellikle sonunda sizin tavsiyeniz.
DavidG

Bu detaylı açıklama için teşekkür ederim. Biri biliyor mu: eğer derleyici katlama değerleri yüzünden aynı wve zaynıysa, bu neden id()referansları kontrol etmek için kullanılsa bile REPL'de çalışıyor ? REPL'i Python 3.7'de kullanma
Chi-chi

8

isyalnızca gerçekte aynı nesneyse true döndürür. Aynı olsalardı, birinde yapılan değişiklik diğerinde de görünürdü. İşte farkın bir örneği.

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]

8

Bir tarafından istendiğinde yinelenen soru , bu benzetme işe yarayabilecek:

# - Darling, I want some pudding!
# - There is some in the fridge.

pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True

# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.

pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False

3
Sadece kişisel zevk olabilir (kelime oyunu değil) ama bu benzetmeyi yararlı olmaktan çok kafa karıştırıcı buldum ve buzdolabımda hiç yokken puding yemek istememe neden oldu :( Sanırım Mark Ransom'un cevabı daha sıkıcı olsa da, muhtemelen daha öğretici
Tom Close

1
@TomClose: Bu soruya pek çok güzel cevap var, yeterince alçakgönüllülük için yer var. Ayrıca puding de istiyorum.
Amadan

5

isve is notPython'daki iki kimlik operatörüdür. isoperatör değişkenlerin değerlerini karşılaştırmaz, ancak değişkenlerin kimliklerini karşılaştırır. Bunu düşün:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> hex(id(a))
'0x1079b1440'
>>> hex(id(b))
'0x107960878'
>>> a is b
False
>>> a == b
True
>>>

Kimlik (ayrıca CPython bellek adresi olabilir) her ikisi için de farklı olduğunu yukarıdaki örnekte gösterildiği Eğer ave b(değerleri aynı olsa bile). Bu nedenle a is b, her iki işlenenin kimliklerindeki uyumsuzluk nedeniyle yanlış döndürdüğünü söylediğinizde . Ancak dediğinizde a == btrue döndürür çünkü ==işlem yalnızca her iki işlenenin de aynı değere sahip olup olmadığını doğrular.

İlginç bir örnek (ekstra not için):

>>> del a
>>> del b
>>> a = 132
>>> b = 132
>>> hex(id(a))
'0x7faa2b609738'
>>> hex(id(b))
'0x7faa2b609738'
>>> a is b
True
>>> a == b
True
>>>

Yukarıdaki örnekte, olsa bile ave biki farklı değişkenler,a is b geri True. Bu türü çünkü aIS intdeğişmez bir amacıdır. Bu yüzden python (sanırım hafızadan tasarruf etmek için) aynı nesneyi baynı değerle oluşturulduğunda tahsis etti . Yani bu durumda, değişkenlerin kimlikleri eşleşti ve olduğu a is bortaya çıktı True.

Bu, tüm değişmez nesneler için geçerli olacaktır:

>>> del a
>>> del b
>>> a = "asd"
>>> b = "asd"
>>> hex(id(a))
'0x1079b05a8'
>>> hex(id(b))
'0x1079b05a8'
>>> a is b
True
>>> a == b
True
>>>

Umarım yardımcı olur.


bu gerçekten güzel bir örnek. detaylı bilgi için teşekkürler.
Haranadh

Ama deneyin a = 123456789 b = 123456789
user2183078

Python'dan daha küçük -5veya daha yüksek olan her şey 256Yanlış olacaktır. Python, [-5, 256] aralığındaki sayıları önbelleğe alır.
akıllı

Gösterdiğiniz gibi tüm değişmez nesneler paylaşılmayacaktır, bu Python çalışma zamanı tarafından bazı nesneler için uygulanan bir optimizasyondur, ancak diğerleri için uygulanmaz. Küçük tam sayıları paylaşma süreci iyi belgelenmiştir, ancak bunun string interning için olduğunu düşünmüyorum .
Mark Ransom

4

x is yid(x) == id(y)nesnelerin kimliğini karşılaştırmakla aynıdır .

@ Tomasz-kurgan'ın aşağıdaki yorumda belirttiği gibi, isoperatör belirli nesnelerle alışılmadık şekilde davranıyor.

Örneğin

>>> class A(object):
...   def foo(self):
...     pass
... 
>>> a = A()
>>> a.foo is a.foo
False
>>> id(a.foo) == id(a.foo)
True

Ref;
https://docs.python.org/2/reference/expressions.html#is-not
https://docs.python.org/2/reference/expressions.html#id24


Değil, değil. Çoğu durumda benzer davranabilir, ancak her zaman doğru değildir. Bkz bu - sayfanın en alt mermi 6 .:> (...) yerine, belirli kullanımlarda görünüşte olağandışı davranış görebilirsiniz olduğunu operatör örnek yöntemlerde, ya sabitler Ve minimum çalışma örnek arasındaki o kapsayan karşılaştırmalar gibi, : `class A (nesne): def foo (self): pass a = A () print a.foo is a.foo print id (a.foo) == id (a.foo)`
Tomasz Kurgan


2

X bir diziyi gösterir, Y farklı bir diziyi gösterir. Bu diziler aynıdır, ancak isoperatör aynı olmayan işaretleyicilere bakacaktır.


5
Python'un işaretçileri yoktur. Terminolojinizi sıkılaştırmanız gerekiyor.
David Heffernan

3
Tıpkı Java ve diğer pek çok dilde olduğu gibi dahili olarak da var. Aslında isoperatörün işlevselliği bunu gösteriyor.
Neko

5
Uygulama ayrıntıları önemli olan değildir. Dokümantasyon "nesne kimliği" terminolojisini kullanır. Sen de yapmalısın. "Operatörler nesne kimliğini test ediyor ve test etmiyor: x, ancak ve ancak x ve y aynı nesne ise doğrudur. X, y değildir, ters doğruluk değerini verir."
David Heffernan

1
@Neko: CPython dahili olarak işaretçiler kullanır. Ancak açıkçası Jython (Java'da uygulanmıştır) ve PyPy (Python'un bir alt kümesinde uygulanmıştır) işaretçi kullanmaz. PyPy'de, idsiz istemedikçe bazı nesnelerin bir bile olmayacaktır .
abarnert

1

Nesne kimliğini, yani değişkenlerin bellekteki aynı nesneyi ifade edip etmediğini karşılaştırır. Sanki ==Java veya C (işaretçiler karşılaştırırken) içinde.


1

Meyvelerle basit bir örnek

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist is newfruitlist )
print ( fruitlist is verynewfruitlist )
print ( newfruitlist is verynewfruitlist )

Çıktı:

True
False
False

Eğer denersen

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist == newfruitlist )
print ( fruitlist == verynewfruitlist )
print ( newfruitlist == verynewfruitlist )

Çıktı farklı:

True
True
True

Bunun nedeni, == operatörünün yalnızca değişkenin içeriğini karşılaştırmasıdır. 2 değişkenin kimliklerini karşılaştırmak için is operatörünü

Kimlik numarasını yazdırmak için:

print ( id( variable ) )

-3

isOperatör şey ama bir İngiliz versiyonu ==. İki listenin kimlikleri farklı olduğu için yanıt yanlıştır. Deneyebilirsin:

a=[1,2,3]
b=a
print(b is a )#True

* Çünkü her iki listenin kimlikleri aynı olacaktır


is'in İngilizce versiyonu ==' değil
David Buck
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.