2012-06-03 11 views
5

Questo è un tentativo di comprendere meglio come funziona il conteggio dei riferimenti in Python.Informazioni sul conteggio dei riferimenti della variabile di classe

Creiamo un corso e lo istanziamo. conteggio di riferimento del grado sarebbe 1 (getrefcount display 2 perché è proprie strutture interne riferimento che un'istanza di classe aumentare conteggio di riferimento da 1):

>>> from sys import getrefcount as grc 
>>> class A(): 
    def __init__(self): 
     self.x = 100000 


>>> a = A() 
>>> grc(a) 
2 

s' a variabili interne x dispone 2 riferimenti:

>>> grc(a.x) 
3 

Mi aspettavo che fosse referenziato dal a e dal metodo __init__A. Quindi ho deciso di controllare.

Così ho creato una variabile temporanea b nello spazio dei nomi __main__ solo per poter accedere alla variabile x. E 'aumentato il ref-numero per 1 per farlo diventare 3 (come previsto):

>>> b = a.x 
>>> grc(a.x) 
4 

Poi ho cancellato l'istanza della classe e il conteggio ref diminuito del 1:

>>> del a 
>>> grc(b) 
3 

Così ora ci sono 2 riferimenti: uno è di b e uno è di A (come mi aspettavo).

Eliminando lo spazio dei nomi A da __main__, il conteggio diminuirà di 1.

>>> del A 
>>> grc(b) 
3 

Ma non succede. Non esiste una classe A o le sue istanze che possono fare riferimento a 100000, ma è comunque referenziata da qualcosa di diverso da b nello spazio dei nomi __main__.

Quindi, la mia domanda è, che cos'è 100000 a cui si fa riferimento a parte da b?


BrenBarn ha suggerito che dovrei usare object() invece di un numero che può essere memorizzato da qualche parte internamente.

>>> class A(): 
    def __init__(self): 
     self.x = object() 


>>> a = A() 
>>> b = a.x 
>>> grc(a.x) 
3 
>>> del a 
>>> grc(b) 
2 

Dopo aver eliminato l'istanza a c'erano solo riferimento da b che è molto logico.

L'unica cosa che rimane da capire è il motivo per cui non è così con il numero 100000.

+0

Secondo me, 'A .__ dict__'? –

+0

@JakobBowyer Ma quando elimino 'A', quindi' A .__ dict__' dovrebbe essere garbage collection perché non è referenziato da nulla (come ho capito). – ovgolovin

+1

Vedere questa risposta: http://stackoverflow.com/questions/759740/unexpected-result-from-sys-getrefcount –

risposta

2

a.x è l'intero 10000. Questa costante fa riferimento all'oggetto codice corrispondente al metodo __init__() di A. oggetti di codice sono sempre comprensivi di riferimenti a tutte le costanti letterali nel codice:

>>> def f(): return 10000 
>>> f.__code__.co_consts 
(None, 10000) 

La linea

del A 

elimina solo il nome A e diminuisce il conteggio dei riferimenti di A. In Python 3.x (ma non in 2.x), le classi spesso includono alcuni riferimenti ciclici e quindi sono solo garbage collection quando si esegue esplicitamente il garbage collector. E in effetti, usando

import gc 
gc.collect() 

dopo del A consentono di giungere alla riduzione del numero di riferimento di b.

+0

La cancellazione di 'A' non dovrebbe eliminare __init__' poiché viene fatto riferimento solo a' A' (come ho capito)? – ovgolovin

+0

Oh. Ora vedo. Il conteggio dei riferimenti di 'A' è' 4' prima di cancellare da '__main__'. Quindi questa eliminazione la ridurrà solo di '1'. Quali sono gli altri oggetti che fanno riferimento a 'A'? – ovgolovin

+0

@ovgolovin: Ho appena notato che non riesco a riprodurre i risultati. Per me, il '' A' di clas effettivamente * fa * viene cancellato, e il conteggio di riferimento di 'b' * diminuisce *. L'unica altra cosa a cui riesco a pensare: fai attenzione con il '_' dell'interprete interattivo. In caso di dubbio, è meglio fare esperimenti con i conteggi di riferimento in uno script piuttosto che nell'interprete interattivo. –

2

È probabile che si tratti di un artefatto in cui si utilizza un numero intero come valore di test. Python a volte memorizza oggetti interi per riutilizzarli in seguito, perché sono immutabili. Quando eseguo il tuo codice utilizzando invece self.x = object() (che creerà sempre un oggetto nuovo di zecca per x), ricevo grc(b)==2 alla fine.

+0

Hai ragione! La modifica di '100000' in' object() 'ha modificato i numeri restituiti a' getrefcount'. Aggiornerò la domanda – ovgolovin

+0

@ovgolovin: Certo che lo è, perché l'oggetto codice può fare riferimento solo a * costanti * che appaiono nel codice. Tuttavia, questo non è completamente correlato a qualsiasi riutilizzo di oggetti interi. I numeri interi non vengono memorizzati in modo casuale nella cache per un successivo riutilizzo. Python contiene solo una cache di piccoli interi (di solito da -5 a 256), che vengono creati all'avvio dell'interprete e utilizzati ogni volta che è necessario. Tutti gli altri numeri interi vengono creati su richiesta e mai riutilizzati. –

+0

Downvoting: mentre l'osservazione è accurata, la motivazione fornita in questa risposta è errata. –

Problemi correlati