Подтвердить что ты не робот

Доступ к адресу памяти объекта

Когда вы вызываете метод object.__repr__() в Python, вы получаете что-то вроде этого:

<__main__.Test object at 0x2aba1c0cf890> 

Есть ли способ получить адрес памяти, если вы перегрузите __repr__(), кроме вызова super(Class, obj).__repr__() и его регулярного выражения?

4b9b3361

Ответ 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>'