Lorsque vous appelez la méthode object.__repr__()
dans Python, vous obtenez quelque chose comme ceci:
<__main__.Test object at 0x2aba1c0cf890>
Existe-t-il un moyen de récupérer l'adresse de la mémoire si vous surchargez __repr__()
, autrement qu'en appelant super(Class, obj).__repr__()
et en l'exécutant?
Le manuel Python dit ceci à propos de id()
:
Renvoie l '"identité" d'un objet. Il s'agit d'un entier (ou entier long) qui est garanti d'être unique et constant pour cet objet tout au long de sa vie. Deux objets dont la durée de vie ne se chevauchent pas peuvent avoir la même valeur id (). (Note d'implémentation: il s'agit de l'adresse de l'objet.)
Donc, dans CPython, ce sera l'adresse de l'objet. Aucune garantie de ce type pour tout autre Python, cependant.
Notez que si vous écrivez une extension C, vous avez un accès complet aux éléments internes de l’interprète Python, y compris l’accès direct aux adresses des objets.
Vous pouvez réimplémenter le repr par défaut de cette façon:
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
Juste utiliser
id(object)
Il y a quelques problèmes ici qui ne sont couverts par aucune des autres réponses.
Tout d'abord, id
renvoie uniquement:
"l'identité" d'un objet. C'est un entier (ou un entier long) qui est garanti d'être unique et constant pour cet objet pendant sa durée de vie. Deux objets dont la durée de vie ne se chevauchent pas peuvent avoir la même valeur
id()
.
Dans CPython, il s’agit du pointeur sur le PyObject
qui représente l’objet dans l’interpréteur, ce qui est la même chose que object.__repr__
. Mais ceci est juste un détail d’implémentation de CPython, pas quelque chose qui est vrai de Python en général. Jython ne traite pas les pointeurs, il traite dans Java références (ce que la machine virtuelle Java représente bien sûr probablement comme des pointeurs, mais vous ne pouvez pas les voir et vous ne voudriez pas, car le GC est autorisé à les déplacer.) PyPy permet à différents types d’avoir différents types de id
, mais le plus général est juste un index dans une table d'objets que vous avez appelée id
, ce qui ne sera évidemment pas un pointeur. Je ne suis pas sûr pour IronPython, mais je suspecterais à cet égard, il ressemble plus à Jython qu'à CPython. Donc, dans la plupart des implémentations Python, il n'y a aucun moyen d'obtenir ce qui est apparu dans ce repr
, et cela ne sert à rien si vous le faisiez. .
Mais que se passe-t-il si vous ne vous souciez que de CPython? C'est un cas assez commun, après tout.
Tout d’abord, vous remarquerez peut-être que id
est un entier; * si vous voulez que la chaîne 0x2aba1c0cf890
au lieu du nombre 46978822895760
, vous devrez la formater vous-même. Sous les couvertures, je crois que object.__repr__
utilise finalement le format %p
de printf
, que vous n'avez pas dans Python… mais vous pouvez toujours le faire:
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* Dans 3.x, c'est un int
. Dans 2.x, c'est un int
s'il est assez gros pour contenir un pointeur (ce qui n'est peut-être pas dû à des problèmes de numéros signés sur certaines plates-formes) et un long
sinon.
Y a-t-il quelque chose que vous puissiez faire avec ces pointeurs en plus de les imprimer? Bien sûr (encore une fois, en supposant que vous ne vous souciez que de CPython).
Toutes les fonctions C API prennent un pointeur sur un PyObject
ou un type associé. Pour ces types liés, vous pouvez simplement appeler PyFoo_Check
pour vous assurer qu'il s'agit bien d'un objet Foo
, puis transtyper avec (PyFoo *)p
. Donc, si vous écrivez une extension C, le id
est exactement ce dont vous avez besoin.
Que faire si vous écrivez un code pur Python?)? Vous pouvez appeler exactement les mêmes fonctions avec pythonapi
à partir de ctypes
.
Enfin, quelques-unes des autres réponses ont évoqué ctypes.addressof
. Ce n'est pas pertinent ici. Cela ne fonctionne que pour les objets ctypes
tels que c_int32
(et peut-être quelques objets de type mémoire tampon, comme ceux fournis par numpy
). Et, même là, il ne vous donne pas l'adresse de la valeur c_int32
, il vous donne l'adresse du niveau C int32
que le c_int32
termine.
Cela étant dit, le plus souvent, si vous pensez vraiment avoir besoin de l'adresse de quelque chose, vous ne voulez pas d'objet natif Python en premier lieu, vous voulez un ctypes
objet.
Juste en réponse à Torsten, je n’ai pas pu appeler addressof()
avec un objet python régulier. En outre, id(a) != addressof(a)
. Ceci est en CPython, Je ne sais rien d'autre.
>>> 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
Avec ctypes , vous pouvez obtenir la même chose avec
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Documentation:
addressof(C instance) -> integer
Renvoie l'adresse du tampon interne de l'instance C
Notez que dans CPython, actuellement id(a) == ctypes.addressof(a)
, mais ctypes.addressof
Devrait renvoyer la véritable adresse pour chaque Python, si
Edit : ajout d'informations sur l'indépendance de l'interpréteur des ctypes
Vous pouvez obtenir quelque chose d’approprié à cet effet avec:
id(self)
S'il est vrai que id(object)
obtient l'adresse de l'objet dans l'implémentation CPython par défaut, c'est généralement inutile ... vous ne pouvez pas faire tout ce qui a l’adresse de pure Python.
Le seul moment où vous seriez réellement en mesure d'utiliser l'adresse provient d'une bibliothèque d'extension C ... auquel cas il est trivial d'obtenir l'adresse de l'objet depuis Python sont toujours transmis en tant que C pointeurs.