È divertente leggere il codice sorgente di Python2.7 che è molto ben scritto e chiaro da leggere. (Mi riferisco alla versione 2.7.12 se vuoi giocare a casa.) Un buon punto di partenza per capire il codice è l'eccellente serie di lezioni: C Python Internals che parte dal punto di vista di un principiante.
Il codice critico (scritto in C) relativo a noi appare nel file "Objects/intobject.c" (Ho rimosso un po 'di codice #ifdef e leggermente modificato la creazione di un nuovo oggetto Integer per chiarezza):
#define NSMALLPOSINTS 257
#define NSMALLNEGINTS 5
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
PyObject *
PyInt_FromLong(long ival)
{
register PyIntObject *v;
if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
v = small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
return (PyObject *) v;
}
/* Inline PyObject_New */
v = (PyIntObject *)Py_TYPE(v);
PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
return (PyObject *) v;
}
Quindi, in sostanza, crea un array preimpostato contenente tutti i numeri compresi tra -5 e 256 e utilizza tali oggetti (aumentando il numero di riferimenti usando la macro Py_INCREF) se possibile. In caso contrario, creerà un oggetto PyInt_Type nuovo di zecca, che viene inizializzato con un conteggio di riferimento pari a 1.
Il mistero del motivo per cui ogni numero sembra avere un conteggio di riferimento di 3 (in realtà quasi qualsiasi nuovo oggetto) viene rivelato solo quando si guarda il codice byte generato da Python. La Macchina Virtuale opera con uno stack di valori (un po 'come in Forth), e ogni volta che un oggetto viene posto sullo stack di valori, incrementa il conteggio dei riferimenti.
Quindi quello che sospetto che stia accadendo è che il tuo codice fornisce di per sé tutti e 3 i riferimenti che vedi, poiché per i numeri che non sono nell'elenco di valori piccoli, dovresti ottenere un oggetto unico. Il primo riferimento è presumibilmente nello stack di valori per il chiamante di getrefcount quando effettua la chiamata; il secondo è nell'elenco delle variabili locali per il frame getrefcount; il terzo è probabile sullo stack di valori nel frame getrefcount mentre cerca il suo conteggio dei riferimenti.
Uno strumento utile se si desidera approfondire ulteriormente il problema sono il comando 'compile' e il comando 'dis' (disassemblare) che si trova nel modulo 'dis', che insieme consentiranno di leggere l'effettivo codice byte generato da qualsiasi parte del codice Python e dovrebbe aiutarti a scoprire esattamente quando e dove viene creato il terzo riferimento.
Per quanto riguarda i conteggi di riferimento più elevati per valori piccoli, quando si avvia Python, carica automaticamente l'intera libreria standard e viene eseguito un bel po 'di codice di inizializzazione del modulo Python prima di iniziare a interpretare il proprio codice. Questi moduli contengono le proprie copie di molti degli interi piccoli (e dell'oggetto None che è anche unico).
Provare 'sys.getrefcount (257)' e probabilmente diminuirà notevolmente. –
Prova 'sys.getrefcount (None)' per un numero interessante. – cdarke
Questo è davvero strano, non ho mai creato una var con 257. Perché restituisce 3? –