2013-03-03 19 views
10

Sadece etkileşimli bir Python oturumunda gerçekleşen, ancak bir komut dosyası yazıp çalıştırdığımda olmayan bu tuhaf davranışa rastladım.Python: yorumlayıcısındaki id() davranışı

Dize dolayısıyla Python değişmez bir veri türüdür: Artık

>>> s2='string' 
>>> s1='string' 
>>> s1 is s2 
True 

garip kısmı:

>>> s1='a string' 
>>> s2='a string' 
>>> s1 is s2 
False 

Ben dizesinde bir boşluk olan bu davranışı neden olduğunu gördük. Bunu bir komut dosyasına koyar ve çalıştırırsam, sonuç her iki durumda da doğrudur.

Bunun hakkında bir ipucu olur mu? Teşekkürler.

DÜZENLEME:

Tamam, yukarıdaki soru ve cevaplar bazı fikirler verebilir. Şimdi burada başka bir deneydir: dizeleri kesinlikle uzun 'a string' daha vardır Bu durumda

>>> s2='astringbstring' 
>>> s1='astringbstring' 
>>> s1 is s2 
True 

ama hala aynı tanımlayıcıları yaşıyoruz.

+1

Bu gönderiye bakın http://stackoverflow.com/questions/2123925/when-does-python-allocate-new-memory-for-identical-strings – isedev

+1

Dahili kuralların Python uygulamaları ve sürümleri arasında farklılık gösterebileceğini unutmayın. Deyimsel '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''' '' ifadesi Python’da son derece nadirdir; Değer eşitliğinden ziyade sadece nesne kimliği ile ilgilendiğinizde kullanmalısınız. –

cevap

6

Düzeltmeler için @eryksun'a çok teşekkürler!

Bunun nedeni Python bir mekanizma çağrısı interning taşımaktadır:

“enterne” dizeleri tabloda dizesi girin ve staj dize döndürür - dize kendisi ya da bir kopyasıdır. Dahili dizeler sözlük aramada küçük bir performans elde etmek için kullanışlıdır - bir sözlükteki anahtarları içeri alındıysa ve arama anahtarı içerse, anahtar karşılaştırmaları (karmalamadan sonra) bir işaretçi tarafından yapılabilir, bir işaretçi yerine dizi karşılaştırması. Normal olarak, Python programlarında kullanılan adlar otomatik olarak içe aktarılır ve modülü, sınıf veya örnek özniteliklerini tutmak için kullanılan sözlükler dahili anahtarlara sahiptir.

Sürüm 2.3 olarak değiştirildi: Dahili dizeler ölümsüz değil ( , Python 2.2 ve daha önceki sürümlerinde kullanılmışlardır); bundan yararlanabilmek için intern() etrafındaki dönüş değerini referans göstermelisiniz.

CPython otomatik stajyer kısa belli dizeleri (1 harf dizeleri, anahtar kelimeler, atanmış boşluksuz dizeleri) arama hızını ve karşılaştırma hızını artırmak olacaktır. Örn 'dog' is 'dog' yerine işaretçi karşılaştırma olacak Tam bir dizge karşılaştırması. Bununla birlikte, tüm (daha uzun) diziler için otomatik internasyon, her zaman mümkün olmayan çok daha fazla belleğe ihtiyaç duyar ve bu nedenle, örneğin, id()'un sonuçlarını farklı yapan aynı kimliği paylaşmayabilirler.,:

en azından benim makinede tamsayılar için
# different id when not assigned 
In [146]: id('dog') 
Out[146]: 4380547672 

In [147]: id('dog') 
Out[147]: 4380547552 

# if assigned, the strings will be interned (though depends on implementation) 
In [148]: a = 'dog' 

In [149]: b = 'dog' 

In [150]: id(a) 
Out[150]: 4380547352 

In [151]: id(b) 
Out[151]: 4380547352 

In [152]: a is b 
Out[152]: True 

, CPython otomatik stajyer kadar otomatik 256 olacaktır:

In [18]: id(256) 
Out[18]: 140511109257408 

In [19]: id(256) 
Out[19]: 140511109257408 

In [20]: id(257) 
Out[20]: 140511112156576 

In [21]: id(257) 
Out[21]: 140511110188504 

GÜNCELLEME sayesinde @eryksun için: Bu durumda dize içinde 'a string' içersinde bulunmuyor çünkü CPython only interns strings without spaces, anımsattığım uzunluk nedeniyle değil: örneğin, ASCII harfleri, rakamları ve alt çizgi.

Daha fazla ayrıntı için, Alex Martelli's answer here'a da bakabilirsiniz.

+0

Cevabınız için teşekkür ederiz. Yukarıdaki EDIT'ime bakın. –

+2

@Amit: Dizgedeki boşluk karakteri. Bir CPython kod nesnesi, yalnızca tüm "isim karakterleri" (ASCII harfleri, rakamlar ve alt çizgi) olan dizge sabitlerini düzenler. Bkz. CPython 2.7.3 [codeobject.c] (http://hg.python.org/cpython/file/70274d53c1dd/Objects/codeobject.c#l71). – eryksun

+0

@eryksun eklediğiniz için teşekkürler, boşlukların dahil edilmediğini tamamen unuttum. –