Python dizesi interneti


92

Bu sorunun pratikte herhangi bir kullanımı olmasa da, Python'un string interneti nasıl yaptığını merak ediyorum. Aşağıdakileri fark ettim.

>>> "string" is "string"
True

Bu beklediğim gibi.

Bunu da yapabilirsiniz.

>>> "strin"+"g" is "string"
True

Ve bu oldukça zekice!

Ama bunu yapamazsın.

>>> s1 = "strin"
>>> s2 = "string"
>>> s1+"g" is s2
False

Python neden değerlendirip s1+"g"aynı olduğunu fark s2edip aynı adrese işaret etmesin? Son blokta, geri dönmesi için gerçekte neler oluyor False?

Yanıtlar:


95

Bu uygulamaya özgüdür, ancak yorumlayıcınız büyük olasılıkla derleme zamanı sabitlerini inceler, ancak çalışma zamanı ifadelerinin sonuçlarını değil.

Aşağıda CPython 2.7.3 kullanıyorum.

İkinci örnekte ifade "strin"+"g", derleme zamanında değerlendirilir ve ile değiştirilir "string". Bu, ilk iki örneğin aynı davranmasını sağlar.

Bayt kodlarını incelersek, tamamen aynı olduklarını göreceğiz:

  # s1 = "string"
  2           0 LOAD_CONST               1 ('string')
              3 STORE_FAST               0 (s1)

  # s2 = "strin" + "g"
  3           6 LOAD_CONST               4 ('string')
              9 STORE_FAST               1 (s2)

Üçüncü örnek, sonucu otomatik olarak dahil edilmeyen bir çalışma zamanı birleştirmesini içerir:

  # s3a = "strin"
  # s3 = s3a + "g"
  4          12 LOAD_CONST               2 ('strin')
             15 STORE_FAST               2 (s3a)

  5          18 LOAD_FAST                2 (s3a)
             21 LOAD_CONST               3 ('g')
             24 BINARY_ADD          
             25 STORE_FAST               3 (s3)
             28 LOAD_CONST               0 (None)
             31 RETURN_VALUE        

intern()Üçüncü ifadenin sonucunu manuel olarak yapacak olsaydınız, öncekiyle aynı nesneyi elde edersiniz:

>>> s3a = "strin"
>>> s3 = s3a + "g"
>>> s3 is "string"
False
>>> intern(s3) is "string"
True

22
Ve kayıt için: aritmetik sabitleri (işlemleri-hesapla önceden edecek Python'un gözetleme deliği optimizasyonu "string1" + "s2", 10 + 3*20derleme zamanında, vs.), ancak ortaya çıkan sınırları dizileri sadece 20 elemanlarına (önlemek için [None] * 10**1000aşırı sizin bayt kodu genişleyen itibaren). Bu çökmüş bu optimizasyon "strin" + "g"içine "string"; sonuç 20 karakterden kısa.
Martijn Pieters

13
Ve bunu iki kez açıklığa kavuşturmak gerekirse: burada hiç staj yapılmıyor. Değişmez değişmez değerler bunun yerine bayt kodu ile sabitler olarak saklanır. Interning , kodda kullanılan adlar için gerçekleşir, ancak intern()işlev tarafından özellikle dahil edilmedikçe program tarafından oluşturulan dize değerleri için geçerli değildir .
Martijn Pieters

9
internPython 3'te işlev bulmaya çalışanlar için
Timofey Chernousov

1

Dava 1

>>> x = "123"  
>>> y = "123"  
>>> x == y  
True  
>>> x is y  
True  
>>> id(x)  
50986112  
>>> id(y)  
50986112  

Durum 2

>>> x = "12"
>>> y = "123"
>>> x = x + "3"
>>> x is y
False
>>> x == y
True

İd durumda 1 aynıdır ve durumda 2. neden Şimdi, soru şu
durumda 1 olarak, değişmez bir dize atamış "123"etmek xve y.

Dizge değişmez olduğundan, yorumlayıcının dizeyi yalnızca bir kez saklaması ve tüm değişkenleri aynı nesneye işaret etmesi anlamlıdır.
Dolayısıyla kimliği aynı olarak görüyorsunuz.

2. durumda, xbirleştirme kullanarak değiştiriyorsunuz . Hem xve yaynı değerleri değil, aynı kimlik vardır.
Her ikisi de bellekteki farklı nesnelere işaret eder. Dolayısıyla farklı idve isoperatör geri döndüFalse


Nasıl olur da dizeler değişmez olduğundan, x + "3" atamak (ve dizgiyi saklamak için yeni bir nokta aramak) y ile aynı referansa atanmaz?
nicecatch

Çünkü o zaman yeni dizgiyi tüm mevcut dizelerle karşılaştırması gerekir; potansiyel olarak çok pahalı bir işlem. Sanırım bunu, hafızayı azaltmak için atamadan sonra arka planda yapabilirdi, ancak daha sonra daha da garip bir davranışla karşılaşabilirsiniz: id(x) != id(x)örneğin, dize değerlendirme sürecinde taşındığı için.
DylanYoung

1
@AndreaConte, çünkü dizelerin birleştirilmesi, her yeni bir tane oluşturduğunda kullanılan tüm dizelerin havuzuna bakmak gibi ekstra bir iş yapmaz. Öte yandan, yorumlayıcı ifadesini "optimize" x = "12" + "3"içine x = "123"atama aslında arama yapar ve aynı "iç" dizesini bulur böylece (tek bir ifadede iki dize hazır ardışımlanmasıyla) y = "123".
derenio

Aslında, kaynak koddaki her dizge "içselleştirilmiş" ve bu nesnenin diğer yerlerde yeniden kullanılması yerine atamanın arama yapması değildir.
derenio
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.