Доступ к адресу памяти объекта
Когда вы вызываете метод object.__repr__()
в Python, вы получаете что-то вроде этого:
<__main__.Test object at 0x2aba1c0cf890>
Есть ли способ получить адрес памяти, если вы перегрузите __repr__()
, кроме вызова super(Class, obj).__repr__()
и его регулярного выражения?
Ответы
Ответ 1
В руководстве по Python сказано следующее о id()
:
Вернуть "личность" объекта. Это целое число (или длинное целое) который гарантированно будет уникальным и постоянная для этого объекта во время его продолжительность жизни. Два объекта с непересекающиеся времена жизни могут иметь то же значение id(). (Примечание о реализации: это адрес объекта.)
Так что в CPython это будет адрес объекта. Однако нет никакой гарантии для любого другого интерпретатора Python.
Обратите внимание, что если вы пишете расширение C, у вас есть полный доступ к внутренним компонентам интерпретатора Python, включая прямой доступ к адресам объектов.
Ответ 2
Вы могли бы повторно реализовать репозиторий по умолчанию следующим образом:
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
Ответ 3
Просто используйте
id(object)
Ответ 4
Здесь есть несколько вопросов, которые не охватываются никакими другими ответами.
Во-первых, id
возвращает только:
"идентичность" объекта. Это целое число (или длинное целое число), которое гарантировано будет уникальным и постоянным для этого объекта в течение его жизни. Два объекта с неперекрывающимися временами жизни могут иметь одинаковое значение id()
.
В CPython это является указателем на PyObject
, который представляет объект в интерпретаторе, что является тем же самым, что object.__repr__
. Но это всего лишь деталь реализации CPython, а не то, что истинно для Python в целом. Jython не занимается указателями, он ссылается на ссылки на Java (которые, вероятно, JVM, вероятно, представляют собой указатели, но вы не можете их видеть и не захотите, потому что GC разрешено перемещать их). PyPy позволяет различным типам иметь разные типы id
, но самый общий - это просто индекс в таблицу объектов, которые вы назвали id
on, что, очевидно, не будет указателем. Я не уверен в IronPython, но я подозреваю, что это больше похоже на Jython, чем на CPython. Таким образом, в большинстве реализаций Python нет способа получить все, что появилось в этом repr
, и не использовать, если вы это сделали.
Но что, если вы только заботитесь о CPython? В конце концов, это довольно распространенный случай.
Ну, во-первых, вы можете заметить, что id
является целым числом; * если вы хотите, чтобы строка 0x2aba1c0cf890
вместо числа 46978822895760
, вам придется отформатировать ее самостоятельно. Под обложками я полагаю, что object.__repr__
в конечном итоге использует формат printf
%p
, которого у вас нет на Python... но вы всегда можете это сделать:
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* В 3.x это an int
. В 2.x это a int
, если достаточно, чтобы удерживать указатель, который может быть не из-за проблем с номерами сокетов на некоторых платформах, а в противном случае long
.
Есть ли что-нибудь, что вы можете сделать с этими указателями, помимо распечатки? Конечно (при условии, что вы только заботитесь о CPython).
Все функции C API принимают указатель на PyObject
или связанный с ним тип. Для этих связанных типов вы можете просто вызвать PyFoo_Check
, чтобы убедиться, что это действительно объект Foo
, а затем введите (PyFoo *)p
. Итак, если вы пишете расширение C, id
- это именно то, что вам нужно.
Что делать, если вы пишете чистый код Python? Вы можете вызвать те же функции с помощью pythonapi
из ctypes
.
Наконец, некоторые из других ответов вызвали ctypes.addressof
. Это не имеет значения. Это работает только для объектов ctypes
, таких как c_int32
(и, возможно, нескольких объектов, похожих на буфер памяти, таких как объекты, предоставленные numpy
). И даже там он не дает вам адрес значения c_int32
, он дает вам адрес C-уровня int32
, который завершает c_int32
.
Как бы то ни было, если вы действительно думаете, что вам нужен адрес чего-то, вы не хотели бы иметь собственный объект Python, вам нужен объект ctypes
.
Ответ 5
Как раз в ответ на Torsten, я не смог вызвать addressof()
на регулярном объекте python. Кроме того, id(a) != addressof(a)
. Это в CPython, не знаю ни о чем другом.
>>> 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
Ответ 6
С помощью ctypes вы можете добиться того же
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Документация:
addressof(C instance) → integer
Вернуть адрес внутреннего буфера экземпляра C
Обратите внимание, что в CPython в настоящее время id(a) == ctypes.addressof(a)
, но ctypes.addressof
должен возвращать реальный адрес для каждой реализации Python, если
- ctypes поддерживается
- указатели памяти являются верным понятием.
Редактировать: добавлена информация о независимости интерпретатора ctypes
Ответ 7
Вы можете получить что-то подходящее для этой цели с помощью:
id(self)
Ответ 8
Хотя верно, что id(object)
получает адрес объекта в реализации CPython по умолчанию, это обычно бесполезно... вы не можете делать что-либо с адресом из чистого кода Python.
Единственный раз, когда вы действительно сможете использовать адрес, - это библиотека расширений C... в этом случае тривиально получить адрес объекта, поскольку объекты Python всегда передаются как C-указатели.
Ответ 9
Я знаю, что это старый вопрос, но если вы все еще программируете, в Python 3 в эти дни... Я действительно обнаружил, что если это строка, то есть действительно простой способ сделать это:
>>> spam.upper
<built-in method upper of str object at 0x1042e4830>
>>> spam.upper()
'YO I NEED HELP!'
>>> id(spam)
4365109296
Преобразование строк также не влияет на расположение в памяти:
>>> spam = {437 : 'passphrase'}
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
>>> str(spam)
"{437: 'passphrase'}"
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'