Domanda

Quando chiami l'oggetto .__ repr __ () in Python ottieni qualcosa del genere indietro:

<__main__.Test object at 0x2aba1c0cf890> 

Esiste un modo per mettere in attesa l'indirizzo di memoria se si sovraccarica __repr __ () , a parte chiamare super (Class, obj) .__ repr __ () e regexing out?

È stato utile?

Soluzione

Il manuale di Python dice questo sull'id () :

  

Restituisce l'identità " '' di un oggetto.   Questo è un numero intero (o numero intero lungo)   che è garantito per essere unico e   costante per questo oggetto durante il suo   tutta la vita. Due oggetti con   le vite senza sovrapposizioni possono avere il   stesso valore id (). (Nota di attuazione:   questo è l'indirizzo dell'oggetto.)

Quindi in CPython, questo sarà l'indirizzo dell'oggetto. Nessuna garanzia del genere per nessun altro interprete Python, tuttavia.

Nota che se stai scrivendo un'estensione C, hai pieno accesso agli interni dell'interprete Python, incluso l'accesso diretto agli indirizzi degli oggetti.

Altri suggerimenti

È 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))
    )

Usa solo

id(object)

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 valore id () .


In CPython, questo sembra essere il puntatore al PyObject che rappresenta l'oggetto nell'interprete, che è la stessa cosa che viene visualizzato object .__ repr__ . Ma questo è solo un dettaglio di implementazione di CPython, non qualcosa che è vero per Python in generale. Jython non ha a che fare con i puntatori, ma con i riferimenti Java (che la JVM ovviamente rappresenta come puntatori, ma non è possibile visualizzarli - e non vorrebbe farlo, 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 su cui hai chiamato id , che ovviamente non sta per essere 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 quel repr , e inutile se lo facessi.


Ma cosa succede se ti interessa solo CPython? Questo è un caso abbastanza comune, dopo tutto.

Bene, per prima cosa potresti notare che id è un numero intero; * se vuoi quella stringa 0x2aba1c0cf890 invece del numero 46978822895760 , dovrai formattarlo tu stesso. Sotto le copertine, credo che object .__ repr__ stia usando il formato printf % p , 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 se è abbastanza grande da contenere un puntatore, il che potrebbe non essere dovuto a problemi di numeri firmati su alcune piattaforme e un lungo in caso contrario.

C'è qualcosa che puoi fare con questi puntatori oltre a stamparli? Sicuro (di nuovo, supponendo che ti interessi solo di CPython).

Tutte le API C indicano un < codice> PyObject o un tipo correlato. Per questi tipi correlati, puoi semplicemente chiamare PyFoo_Check per assicurarti che sia davvero un oggetto Foo , quindi trasmettere con (PyFoo *) p . Quindi, se stai scrivendo un'estensione C, id è esattamente ciò di cui hai bisogno.

Cosa succede 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 oggetti ctypes come c_int32 (e forse alcuni oggetti simili a buffer di memoria, come quelli forniti da numpy ). E, anche lì, non ti dà l'indirizzo del valore c_int32 , ti sta dando l'indirizzo del livello C int32 che c_int32 termina.

Detto questo, il più delle volte, se pensi davvero di aver bisogno dell'indirizzo di qualcosa, non volevi in ??primo luogo un oggetto Python nativo, ma volevi un oggetto ctypes .

Proprio in risposta a Torsten, non sono stato in grado di chiamare addressof () su 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 ctypes , puoi ottenere la stessa cosa con

>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L

Documentazione:

  

indirizzoof (istanza C) - > intero
  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

  • ctypes è supportato
  • i puntatori di memoria sono una nozione valida.

Modifica : aggiunte informazioni sull'indipendenza dell'interprete dei tipi

Puoi ottenere qualcosa adatto a quello scopo con:

id(self)

Mentre è vero che id (oggetto) ottiene l'indirizzo dell'oggetto nell'implementazione predefinita di CPython, questo è generalmente inutile ... non puoi fare niente con 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top