2010-01-13 8 views
10

Eventuali duplicati:
Python “is” operator behaves unexpectedly with integersPython identità: disturbo di personalità multipla, ha bisogno del codice shrink

mi sono imbattuto il seguente Python weirdity:

>>> two = 2 
>>> ii = 2 

>>> id(two) == id(ii) 
True 
>>> [id(i) for i in [42,42,42,42]] 
[10084276, 10084276, 10084276, 10084276] 

>>> help(id) 
Help on built-in function id in module __builtin__: 

id(...) 
    id(object) -> integer 

    Return the identity of an object. This is guaranteed to be unique among 
    simultaneously existing objects. (Hint: it's the object's memory address.) 
  1. è ogni numbe r un oggetto unico?
  2. Sono variabili diverse che mantengono gli stessi valori elementali (ad esempio, due, ii) lo stesso oggetto?
  3. Come è l'id di un numero generato da Python?
  4. Nell'esempio precedente, due e ii puntatori a una cella di memoria contenente il valore 2? Sarebbe estremamente strano.

Aiutami a districare questa crisi di identità.

Alcune altre Bizzarrie:

>>> a,b=id(0),id(1) 
>>> for i in range(2,1000): 
    a,b=b,id(i) 
    if abs(a-b) != 12: 
    print('%i:%i -> %i' % (i,a,b)) 

Il codice sopra esamina se ids di interi consecutivi sono consecutivi, e stampa anomalie:

77:10083868 -> 10085840 
159:10084868 -> 10086840 
241:10085868 -> 10087840 
257:10087660 -> 11689620 
258:11689620 -> 11689512 
259:11689512 -> 11689692 
260:11689692 -> 11689548 
261:11689548 -> 11689644 
262:11689644 -> 11689572 
263:11689572 -> 11689536 
264:11689536 -> 11689560 
265:11689560 -> 11689596 
266:11689596 -> 11689656 
267:11689656 -> 11689608 
268:11689608 -> 11689500 
331:11688756 -> 13807288 
413:13806316 -> 13814224 
495:13813252 -> 13815224 
577:13814252 -> 13816224 
659:13815252 -> 13817224 
741:13816252 -> 13818224 
823:13817252 -> 13819224 
905:13818252 -> 13820224 
987:13819252 -> 13821224 

noti che emerge un modello da 413 in poi. Forse è dovuto ad una contabilità voodoo all'inizio di ogni nuova pagina di memoria.

+1

Che importa? Perché stai chiedendo? Che problema ha questa causa? Non capisco la domanda. Per favore chiarisci cosa è rotto. –

+3

@ S.Lott Sta cercando di approfondire la sua comprensione, cosa c'è di sbagliato in questo? A volte il viaggio vale più della destinazione. – Simon

+1

Non capisco la domanda. Non posso aiutare ad approfondire la comprensione se la domanda è opaca. –

risposta

4

La quarta domanda, "nell'esempio precedente, sono due e ii puntatori a una cella di memoria che contiene il valore 2? Che sarebbe estremamente strano", è davvero la chiave per comprendere l'intera cosa.

Se hai familiarità con linguaggi come C, le "variabili" di Python non funzionano nello stesso modo. AC dichiarazione di variabile come:

int j=1; 
int k=2; 
k += j; 

dice: "compilatore, riserva per me le due aree di memoria, in pila, ciascuno con spazio sufficiente per contenere un numero intero, e ricordare una come 'j' e l'altro come ' k '. Quindi inserisci j con il valore' 1 'e k con il valore' 2 '. " In fase di esecuzione, il codice dice "prendi il contenuto intero di k, aggiungi il contenuto intero di j e memorizza il risultato su k".

Il codice apparentemente equivalente in Python:

j = 1 
k = 2 
k += j 

dice qualcosa di diverso: "Python, cercare l'oggetto conosciuto come '1', e creare un'etichetta chiamata 'j' che punta ad esso lo sguardo. l'oggetto noto come '2' e crea un'etichetta chiamata 'k' che punta ad esso. Ora cerca l'oggetto 'k' punta a ('2'), cerca l'oggetto 'j' punta a ('1') e punta "k" all'oggetto risultante dall'esecuzione dell'operazione "aggiungi" sui due. "

Smontaggio questo codice (con le dis modulo) lo dimostra bene:

2   0 LOAD_CONST    1 (1) 
       3 STORE_FAST    0 (j) 

    3   6 LOAD_CONST    1 (2) 
       9 STORE_FAST    1 (k) 

    4   12 LOAD_FAST    1 (k) 
      15 LOAD_FAST    0 (j) 
      18 INPLACE_ADD 
      19 STORE_FAST    1 (k) 

Quindi sì, Python "variabili" sono etichette che puntano a oggetti, piuttosto che contenitori che può essere pieno di dati.

Le altre tre domande sono tutte variazioni su "quando Python crea un nuovo oggetto da un pezzo di codice e quando ne riutilizza uno già?". Quest'ultimo è chiamato "interning"; succede a interi più piccoli e stringhe che sembrano (a Python) come potrebbero essere nomi di simboli.

+1

"oggetto noto come '2' e creare un'etichetta chiamata 'j'" che dovrebbe essere '1' –

+0

Grazie, tolomea - risolto! –

9

I numeri interi da -1 a 255 (?), Così come i valori letterali stringa, sono internati. Ogni istanza nella sorgente rappresenta in realtà lo stesso oggetto.

In CPython, il risultato di id() è l'indirizzo nello spazio di elaborazione di PyObject.

+1

Questo è necessariamente necessariamente vero per CPython. E anche lì, nessuno ha garantito che non cambierà, anche durante il congelamento della sintassi. – jcdyer

+0

Vero. Soleva essere fino a 99 circa nelle versioni precedenti. –

2

Dovresti stare molto attento con questo tipo di indagini. Stai esaminando gli aspetti interni dell'implementazione della lingua e quelli non sono garantiti. La guida su id è azzeccata: il numero sarà diverso per due oggetti diversi e lo stesso per lo stesso oggetto. Come dettaglio di implementazione, in CPython è l'indirizzo di memoria dell'oggetto. CPython potrebbe decidere di modificare questo dettaglio in qualsiasi momento.

Il dettaglio degli interi piccoli che vengono internati allo stesso tempo di allocazione è anche un dettaglio che potrebbe cambiare in qualsiasi momento.

Inoltre, se si passa da CPython a Jython o PyPy o IronPython, tutte le scommesse sono disattivate, ad eccezione della documentazione su id().

1

Non tutti i numeri sono oggetti univoci e il fatto che alcuni siano un dettaglio di ottimizzazione dell'interprete CPython. Non fare fare affidamento su questo comportamento. Del resto, non utilizzare mai is per verificare l'uguaglianza. Utilizzare solo is se si è assolutamente certi di aver bisogno dello stesso identico oggetto.

+2

Avvertenza: si deve sempre usare 'is' quando si confronta con' Nessuno'. – jcdyer

+0

E 'Ellipsis'. Anche se non dovrai mai farlo. –

+3

La regola generale, uscita direttamente da PEP-8, è "l'uso è quando si confronta con un oggetto singleton". Ciò significa Nessuno, Vero, Falso, Ellipsis, ecc. Tuttavia, Vero e Falso generalmente sono meglio omessi del tutto, per consentire che la coercizione booleana abbia luogo. –

8

Ogni implementazione di Python è completamente consentita per ottimizzare in qualsiasi misura (compreso .... nessuno affatto ;-) l'identità e l'assegnazione di oggetti immutabili (come numeri, tuple e stringhe) [[no tali esiste latitudine per gli oggetti mutabili, come elenchi, dict e set]].

Tra due riferimenti a oggetti immutabili a e b, tutta l'attuazione deve garantire è:

  1. id(a) == id(b), AKA a is b, deve sempre implicare a == b
  2. e quindi a != b deve sempre implicare id(a) != id(b) AKA a is not b

Nota in particolare c'è no vincolo, anche per tipi immutabili, che a == b deve implicare a is b (ad es. quello id(a) == id(b)). Solo la garanzia None (in questo modo è sempre possibile testare if x is None: anziché if x == None:).

Le attuali implementazioni di CPython sfruttano questi gradi di libertà "unendo" (con una singola allocazione, quindi un singolo id, per) interi piccoli in un determinato intervallo e oggetti di tipo immutabile incorporati i cui valori letterali appaiono più di una sola funzione all'interno di una determinata funzione (ad esempio se la tua funzione f ha quattro occorrenze letterali di 'foobar' tutte si riferiscono a una singola istanza di stringa 'foobar' all'interno delle costanti della funzione, risparmiando un po 'di spazio rispetto all'implementazione consentita che memorizzerebbe quattro identiche ma copie separate di quella costante).

Tutte queste considerazioni sull'implementazione sono di interesse minore per i coder Python (a meno che non si stia lavorando su un'implementazione Python, o almeno qualcosa strettamente legato a un'implementazione specifica, come un sistema di debug).

Problemi correlati