2016-02-08 19 views
9

soruma oldukça benzerdir this ve this, okuduktan sonra, hala şu davranışları anlayamıyorum: Görebildiğim id(a) ve id(b) basarkenPython3 çoklu atama ve bellek adresi

a = 257 
b = 257 
print(a is b) #False 
a, b = 257, 257 
print(a is b) #True 

değişkenler olduğunu,

a = 257 
b = 257 
print(id(a)) #139828809414512 
print(id(b)) #139828809414224 
a, b = 257, 257 
print(id(a)) #139828809414416 
print(id(b)) #139828809414416 

Ama bu imkansız: hangi değerleri çoklu atama ile her iki değer aynı kimliğe sahip ise, ayrı satırlarda farklı kimlikleri var ayrıldı değişkenler aynı id değil olsun açıklıyor net bir kural mı var

a, b = -1000, -1000 
print(id(a)) #139828809414448 
print(id(b)) #139828809414288 

: Aynı değerlerin birden atama hep yana aynı id işaretçileri oluşturur söyleyerek bu davranışı açıklamak için?

düzenlemek

ilgili bilgi: (ipython3)

+0

Kontrol dışarı '[için id (i) i (1000,1000,1000,1000)]' –

+4

Not :-): bu konularda çünkü hiçbir zaman davranış tutarsız. İki 257'nin aynı nesne olup olmadığına bakmak için herhangi bir sebep olsaydı, basit ve mantıklı bir model olurdu. – user2357112

+0

gözetleme deliği optimizasyonları, nasıl çalıştığını veya asla güvenmemesi gereken bir şey olmadığından dolayı alakasız. –

cevap

2

Bu bayt kodu derleyici sabit bir katlama optimizasyonu kaynaklanmaktadır. Baytkod derleyici, bir dizi ifade derlediğinde, gördüğü sabitlerin kaydını tutmak için uses a dict. Bu dict herhangi bir eşdeğer sabitleri otomatik olarak birleştirir.

Burada kayıt ve numaralama sabitleri için rutin sorumlu (yanı sıra birkaç ilişkili sorumluluklar) var:

static int 
compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o) 
{ 
    PyObject *t, *v; 
    Py_ssize_t arg; 

    t = _PyCode_ConstantKey(o); 
    if (t == NULL) 
     return -1; 

    v = PyDict_GetItem(dict, t); 
    if (!v) { 
     arg = PyDict_Size(dict); 
     v = PyInt_FromLong(arg); 
     if (!v) { 
      Py_DECREF(t); 
      return -1; 
     } 
     if (PyDict_SetItem(dict, t, v) < 0) { 
      Py_DECREF(t); 
      Py_DECREF(v); 
      return -1; 
     } 
     Py_DECREF(v); 
    } 
    else 
     arg = PyInt_AsLong(v); 
    Py_DECREF(t); 
    return arg; 
} 

Bunu sadece yeni bir giriş ekler ve bunları yapmazsa yeni bir numara atar görebilirsiniz Halihazırda eşdeğer bir sabit bulun. (_PyCode_ConstantKey bit, 0.0, -0.0 ve 0 gibi öğelerin eş anlamlı olarak kabul edilmesini sağlar.

bir komut dosyası olarak
>>> a = 1000 
>>> b = 1000 
>>> a is b 
False 
>>> a = 1000; b = 1000 # 1 batch 
>>> a is b 
True 

, tüm üst düzey ifadeleri:)

interaktif modda

, bir toplu böylece sabit katlama çoğunlukla komutları arasında olmaz, tercüman aslında komutu çalıştırmak zorundadır her zaman biter bir komut olarak

a = 257 
b = 257 
print a is b 

, bu True yazdırır: böylece more constant folding happens bir toplu vardır.

bir fonksiyon kodu sabit değerlerinin sabit bir katlanmayı fonksiyonu, dış kodundan bağımsız olarak takip alır:

a = 257 

def f(): 
    b = 257 
    print a is b 

f() 

Even in a script

bu False basar.

+0

Teşekkürler. Sorumlu modda test edildiğini açıklamak için sorumu düzenleyeceğim. – istern

+0

Peki python 3'te -5’den küçük tamsayılar nedir? örneğin 'a, b = -6, -6' – Kasramvd

+0

@Kasramvd: derleyici 'LOAD_CONST' ve bir' UNARY_NEGATIVE' içine' -6' derler; Bunu bir "-6" yükleyen bir "LOAD_CONST" 'a dönüştürmekten sorumlu bir [ayrı optimizasyon] (https://hg.python.org/cpython/file/3.5/Python/peephole.c#l242) var. Bu optimizasyon dict kullanmaz. – user2357112

0

Böyle kural yönteme göre değişir bu söz konusu kod etkileşimli modda çalıştırıldı. Örneğin, CPython, küçük bir tam sayı için (-5 - 256) performans optimizasyonu olarak int nesnesini önceden ayırır.

Tek genel kural, herhangi bir kullanımın yeni bir nesne üreteceğini varsaymaktır.

+1

Numara 257'dir ve bu davranışı daha büyük tamsayılar kullanarak da görebilirsiniz. – Kasramvd

+0

Her zaman tam aralığı unutuyorum. – chepner

+0

"üretecek" değil, "üretebilir". – glglgl

2

Bu, const değerlerinin yüklenmesi sırasında, pitonların UNPACK_SEQUENCE saatindeki yorumlayıcı optimizasyonu nedeniyle gerçekleşir. Aslında python paketin açılması sırasında yinelenen bir zamanla karşılaştığında, yinelenen nesneleri birden fazla kez yüklemez ve sadece ilk nesneyi saklar ve tüm adlarınızı tek bir nesne adresine atar. Böylece tüm değişkenleriniz bir nesneye aynı referans olur.

Aslında sizin açma aşağıdaki komutla eşdeğer olacaktır:
a = b = 257 

Ve piton 3.X içinde herhangi bir fark ama yapmaz piton 2.x olumsuz numaraları hakkında

o numaralar için daha küçük görünüyor daha -5 piton açma sırasında yeni bir nesne oluşturur:

>>> a, b = -6, -6 
>>> a is b 
False 
>>> a, b = -5, -5 
>>> 
>>> a is b 
True 
+0

nasıl cevap = -1000, -1000 b bir ile, Soruma son bölümünü açıklıyor? son bölümünde – istern

+0

@isternberg ayrı olarak değişkenler oluşturmak var, ama en kısa zamanda bir nedenle cevap güncellenir python3 açtıktan negatif sayılar başka nokta vardır. – Kasramvd

+0

"tek LOAD_CONSTANT ve 2 STORE_FAST" - Doğru olsak da, 'LOAD_CONSTANT' sabit yükleniyor' tuple' 2 öğe tutan. Aynı kimliğe sahip iki değerin (python'un dahili tam sayılarının normal aralığının dışında olduklarında) bunun nasıl açıklandığı bana açık bir şekilde emin değilim. – mgilson