Réponses:
Le manuel Python a ceci à dire à propos de id()
:
Renvoie "l'identité" d'un objet. Il s'agit d'un entier (ou entier long) qui est garanti unique et constant pour cet objet pendant sa durée de vie. Deux objets dont la durée de vie ne se chevauche pas peuvent avoir la même valeur id (). (Note d'implémentation: c'est l'adresse de l'objet.)
Donc en CPython, ce sera l'adresse de l'objet. Aucune garantie de ce type pour aucun autre interpréteur Python, cependant.
Notez que si vous écrivez une extension C, vous avez un accès complet aux internes de l'interpréteur Python, y compris l'accès aux adresses des objets directement.
lifetime
(et que signifie la durée de vie overlap/not overlap
) dans ce contexte?
Vous pouvez réimplémenter la 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))
)
return object.__repr__(self)
ou même le faire object.__repr__(obj)
chaque fois que vous en avez besoin au lieu de créer une nouvelle classe
__repr__ = object.__repr__
, et n'est pas aussi infaillible, car il existe une variété de situations où cela ne fonctionne pas, par exemple une __getattribute__
implémentation remplacée ou non CPython où l'id n'est pas l'emplacement de la mémoire. Il ne se remplit pas non plus en z, vous devrez donc déterminer si le système est 64 bits et ajouter les zéros si nécessaire.
Juste utiliser
id(object)
id()
@JLT
Il y a quelques problèmes ici qui ne sont couverts par aucune des autres réponses.
Tout d'abord, id
ne renvoie que:
«l'identité» d'un objet. Il s'agit d'un entier (ou entier long) qui est garanti unique et constant pour cet objet pendant sa durée de vie. Deux objets dont les durées de vie ne se chevauchent pas peuvent avoir la même
id()
valeur.
En CPython, il s'agit du pointeur vers le PyObject
qui représente l'objet dans l'interpréteur, qui est la même chose qui object.__repr__
s'affiche. Mais ce n'est qu'un détail d'implémentation de CPython, pas quelque chose qui est vrai de Python en général. Jython ne s'occupe pas des pointeurs, il traite des références Java (que la JVM 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ésid
sur, ce qui ne sera évidemment pas un indicateur. Je ne suis pas sûr d'IronPython, mais je suppose que cela ressemble plus à Jython qu'à CPython à cet égard. Donc, dans la plupart des implémentations Python, il n'y a aucun moyen d'obtenir ce qui s'y trouve repr
, et cela ne sert à rien si vous l'avez fait.
Mais que faire si vous ne vous souciez que de CPython? C'est un cas assez courant, après tout.
Eh bien, tout d'abord, vous remarquerez peut-être que id
c'est un entier; * si vous voulez cette 0x2aba1c0cf890
chaîne au lieu du nombre 46978822895760
, vous devrez la formater vous-même. Sous les couvertures, je pense object.__repr__
qu'en fin de compte, il utilise printf
le %p
format de, que vous n'avez pas de 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
si c'est assez grand pour contenir un pointeur - ce qui peut ne pas être dû à des problèmes de nombres signés sur certaines plates-formes - et un long
autre.
Y a-t-il quelque chose que vous pouvez 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 de l' API C prennent un pointeur vers un PyObject
ou un type associé. Pour ces types associés, vous pouvez simplement appeler PyFoo_Check
pour vous assurer qu'il s'agit bien d'un Foo
objet, puis lancer avec (PyFoo *)p
. Donc, si vous écrivez une extension C, id
c'est exactement ce dont vous avez besoin.
Et si vous écrivez du code Python pur? Vous pouvez appeler exactement les mêmes fonctions avec pythonapi
de ctypes
.
Enfin, quelques-unes des autres réponses ont été soulevées ctypes.addressof
. Ce n'est pas pertinent ici. Cela ne fonctionne que pour des ctypes
objets comme c_int32
(et peut-être quelques objets de type tampon mémoire, comme ceux fournis par numpy
). Et, même là, cela ne vous donne pas l'adresse de la c_int32
valeur, c'est l'adresse du niveau C int32
qui se c_int32
termine.
Cela étant dit, le plus souvent, si vous pensez vraiment avoir besoin de l'adresse de quelque chose, vous ne vouliez pas d'un objet Python natif en premier lieu, vous vouliez un ctypes
objet.
id
- y compris leur utilisation pour contenir des valeurs mutables dans un seen
ensemble ou un cache
dict - ne dépendent d'aucune façon du fait d' id
être un pointeur, ou liées de quelque manière que ce soit au repr
. C'est exactement pourquoi ce code fonctionne dans toutes les implémentations Python, au lieu de fonctionner uniquement en CPython.
id
pour cela, mais je veux dire que même en java, vous pouvez obtenir l'adresse de l'objet, cela semble étrange, il n'y a aucun moyen dans (C) Python car celui-ci a en fait un gc stable qui ne déplace pas les objets, donc l'adresse reste la même
id
fo un objet, que ce soit une adresse ou non. Par exemple, dans PyPy, id
est toujours aussi utile qu'une clé en CPython, même s'il ne s'agit généralement que d'un index dans une table cachée de l'implémentation, mais un pointeur serait inutile, car (comme Java) l'objet peut être déplacé dans Mémoire.
id
d'un objet est le pointeur vers l'emplacement de l'objet en mémoire. Donc, si vous avez une utilisation de la valeur du pointeur (ce que vous ne faites presque jamais, comme expliqué également dans la réponse) dans du code spécifique à CPython, il existe un moyen de l'obtenir qui est documenté et garanti de fonctionner.
Juste en réponse à Torsten, je n'ai pas pu appeler addressof()
un objet Python normal. De plus, id(a) != addressof(a)
. C'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 réaliser 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 l'adresse réelle pour chaque implémentation Python, si
Edit : ajout d'informations sur l'indépendance de l'interpréteur des ctypes
TypeError: invalid type
lorsque je l'essaye avec Python 3.4.
Vous pouvez obtenir quelque chose qui convient à cet effet avec:
id(self)
Je sais que c'est une vieille question, mais si vous êtes encore en train de programmer, en python 3 ces jours-ci ... j'ai en fait trouvé que s'il s'agit d'une chaîne, il existe un moyen très simple de le faire:
>>> spam.upper
<built-in method upper of str object at 0x1042e4830>
>>> spam.upper()
'YO I NEED HELP!'
>>> id(spam)
4365109296
la conversion de chaîne n'affecte pas non plus l'emplacement en mémoire:
>>> spam = {437 : 'passphrase'}
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
>>> str(spam)
"{437: 'passphrase'}"
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
S'il est vrai qu'il 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 rien faire avec l'adresse du code Python pur.
Le seul moment où vous pourriez réellement utiliser l'adresse est à partir d'une bibliothèque d'extensions C ... auquel cas il est trivial d'obtenir l'adresse de l'objet puisque les objets Python sont toujours transmis comme des pointeurs C.
ctypes
boîte à outils intégrée dans la bibliothèque standard. Dans ce cas, vous pouvez faire toutes sortes de choses avec l'adresse :)