Risposte:
Il manuale di Python ha questo da dire su id()
:
Restituisce l '"identità" di un oggetto. Si tratta di un numero intero (o intero lungo) che è garantito essere unico e costante per questo oggetto durante la sua vita. Due oggetti con durata non sovrapposta possono avere lo stesso valore id (). (Nota di implementazione: questo è l'indirizzo dell'oggetto.)
Quindi in CPython, questo sarà l'indirizzo dell'oggetto. Nessuna garanzia del genere per nessun altro interprete Python, comunque.
Nota che se stai scrivendo un'estensione C, hai pieno accesso agli interni dell'interprete Python, incluso l'accesso diretto agli indirizzi degli oggetti.
lifetime
(e cosa significa per tutta la vita overlap/not overlap
) in questo contesto?
È possibile reimplementare il repr predefinito in questo modo:
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
return object.__repr__(self)
o anche solo object.__repr__(obj)
quando ne hai bisogno, invece di fare una nuova lezione
__repr__ = object.__repr__
, e non è altrettanto infallibile, in quanto ci sono una varietà di situazioni in cui questo non funziona, ad esempio __getattribute__
un'implementazione sovrascritta o non CPython dove l'id non è la posizione della memoria. Inoltre non riempie z, quindi dovresti capire se il sistema è a 64 bit e aggiungere gli zeri se necessario.
Basta usare
id(object)
id()
@JLT
Ci sono alcuni problemi qui che non sono coperti da nessuna delle altre risposte.
Innanzitutto, id
restituisce solo:
l '"identità" di un oggetto. Questo è un numero intero (o intero lungo) che è garantito essere unico e costante per questo oggetto durante la sua vita. Due oggetti con durata non sovrapposta possono avere lo stesso
id()
valore.
In CPython, questo sembra essere il puntatore a PyObject
che rappresenta l'oggetto nell'interprete, che è la stessa cosa che object.__repr__
viene visualizzata. Ma questo è solo un dettaglio dell'implementazione di CPython, non qualcosa che è vero per Python in generale. Jython non si occupa di puntatori, si occupa di riferimenti Java (che la JVM ovviamente rappresenta come puntatori, ma non è possibile visualizzarli - e non vorrebbe, perché il GC è autorizzato a spostarli). PyPy consente a diversi tipi di avere diversi tipi di id
, ma il più generale è solo un indice in una tabella di oggetti che hai chiamatoid
on, che ovviamente non sarà un puntatore. Non sono sicuro di IronPython, ma sospetto che sia più simile a Jython che a CPython in questo senso. Quindi, nella maggior parte delle implementazioni di Python, non c'è modo di ottenere ciò che viene mostrato in questo repr
, e inutile se lo facessi.
E se ti interessasse solo CPython? Questo è un caso abbastanza comune, dopo tutto.
Bene, per prima cosa potresti notare che id
è un numero intero; * se vuoi quella 0x2aba1c0cf890
stringa invece del numero 46978822895760
, dovrai formattarla tu stesso. Sotto le copertine, credo che alla object.__repr__
fine stia usando printf
il %p
formato, che non hai da Python ... ma puoi sempre farlo:
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* In 3.x, è un int
. In 2.x, è un int
if abbastanza grande da contenere un puntatore, il che potrebbe non essere dovuto a problemi di numeri firmati su alcune piattaforme e un long
altro.
C'è qualcosa che puoi fare con questi puntatori oltre a stamparli? Sicuro (di nuovo, supponendo che ti interessi solo di CPython).
Tutte le funzioni dell'API C portano un puntatore a uno PyObject
o un tipo correlato. Per quei tipi correlati, puoi semplicemente chiamare PyFoo_Check
per assicurarti che sia davvero un Foo
oggetto, quindi eseguire il cast (PyFoo *)p
. Quindi, se stai scrivendo un'estensione C, id
è esattamente quello che ti serve.
E se stai scrivendo puro codice Python? Puoi chiamare le stesse identiche funzioni con pythonapi
da ctypes
.
Infine, alcune delle altre risposte hanno sollevato ctypes.addressof
. Questo non è rilevante qui. Funziona solo con ctypes
oggetti come c_int32
(e forse alcuni oggetti simili a buffer di memoria, come quelli forniti da numpy
). E, anche lì, non ti sta dando l'indirizzo del c_int32
valore, ti sta dando l'indirizzo del livello C int32
che c_int32
racchiude.
Detto questo, il più delle volte, se davvero pensi di aver bisogno dell'indirizzo di qualcosa, in primo luogo non volevi un ctypes
oggetto nativo di Python, ma volevi un oggetto.
id
—includere l'uso di questi per contenere valori mutabili in un seen
set o in un cache
dict — non dipendono in alcun modo id
dall'essere un puntatore o in alcun modo correlato al repr
. Questo è esattamente il motivo per cui tale codice funziona in tutte le implementazioni di Python, invece di funzionare solo in CPython.
id
per questo, ma voglio dire che anche in Java puoi ottenere l'indirizzo dell'oggetto, sembra strano che non ci sia modo in (C) Python poiché quello ha effettivamente un gc stabile che non sposta gli oggetti, quindi l'indirizzo rimane lo stesso
id
fo un oggetto, che sia o meno un indirizzo. Ad esempio, in PyPy, id
è ancora utile quanto una chiave in CPython, anche se di solito è solo un indice in una tabella nascosta nell'implementazione, ma un puntatore sarebbe inutile, perché (come Java) l'oggetto può essere spostato in memoria.
id
of of a object è il puntatore alla posizione dell'oggetto in memoria. Quindi, se hai qualche utilità per il valore del puntatore (cosa che non fai quasi mai, come spiegato anche nella risposta) nel codice specifico di CPython, c'è un modo per farlo documentato e garantito che funzioni.
Proprio in risposta a Torsten, non sono stato in grado di chiamare addressof()
un normale oggetto Python. Inoltre, id(a) != addressof(a)
. Questo è in CPython, non so nient'altro.
>>> from ctypes import c_int, addressof
>>> a = 69
>>> addressof(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: invalid type
>>> b = c_int(69)
>>> addressof(b)
4300673472
>>> id(b)
4300673392
Con i tipi , puoi ottenere la stessa cosa con
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Documentazione:
addressof(C instance) -> integer
Restituisce l'indirizzo del buffer interno dell'istanza C.
Nota che in CPython, attualmente id(a) == ctypes.addressof(a)
, ma ctypes.addressof
dovrebbe restituire l'indirizzo reale per ogni implementazione di Python, se
Modifica : aggiunte informazioni sull'indipendenza dell'interprete dei tipi
TypeError: invalid type
quando lo provo con Python 3.4.
Puoi ottenere qualcosa adatto a tale scopo con:
id(self)
So che questa è una vecchia domanda, ma se stai ancora programmando, in Python 3 in questi giorni ... Ho effettivamente scoperto che se è una stringa, allora c'è un modo davvero semplice per farlo:
>>> spam.upper
<built-in method upper of str object at 0x1042e4830>
>>> spam.upper()
'YO I NEED HELP!'
>>> id(spam)
4365109296
la conversione di stringhe non influisce sulla posizione in memoria:
>>> spam = {437 : 'passphrase'}
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
>>> str(spam)
"{437: 'passphrase'}"
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
Mentre è vero che id(object)
ottiene l'indirizzo dell'oggetto nell'implementazione predefinita di CPython, questo è generalmente inutile ... non puoi fare nulla con l'indirizzo dal puro codice Python.
L'unica volta in cui potresti effettivamente utilizzare l'indirizzo proviene da una libreria di estensioni C ... nel qual caso è banale ottenere l'indirizzo dell'oggetto poiché gli oggetti Python vengono sempre passati come puntatori C.
ctypes
toolkit integrato nella Libreria standard. Nel qual caso puoi fare ogni sorta di cose con l'indirizzo :)