Вопрос

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

<__main__.Test object at 0x2aba1c0cf890> 

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

Это было полезно?

Решение

А Руководство по Python есть что сказать об этом id():

Возвращает «идентичность» объекта.Это целое число (или длинное целое число), которое гарантированно будет уникальным и постоянным для этого объекта в течение жизни.Два объекта с непересекающим временем жизни могут иметь одинаковое значение ID ().(Примечание по реализации:это адрес объекта.)

Итак, в CPython это будет адрес объекта.Однако такой гарантии нет для любого другого интерпретатора Python.

Обратите внимание: если вы пишете расширение C, у вас есть полный доступ ко внутреннему устройству интерпретатора Python, включая прямой доступ к адресам объектов.

Другие советы

Вы можете переопределить представление по умолчанию следующим образом:

def __repr__(self):
    return '<%s.%s object at %s>' % (
        self.__class__.__module__,
        self.__class__.__name__,
        hex(id(self))
    )

Просто используйте

id(object)

Здесь есть несколько вопросов, которые не охвачены ни одним из других ответов.

Первый, 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's %p формат, которого у вас нет в Python… но вы всегда можете сделать это:

format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')

* В версии 3.x это int.В версии 2.x это 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 объект.

Просто в ответ Торстену я не смог позвонить 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

С cтипы, вы можете добиться того же самого с помощью

>>> 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 от интерпретатора

Вы можете получить что-то подходящее для этой цели с помощью:

id(self)

Хотя это правда, что id(object) получает адрес объекта в реализации CPython по умолчанию, это вообще бесполезно...ты не можешь делать что-нибудь с адресом из чистого кода Python.

Единственный раз, когда вы действительно сможете использовать адрес, - это библиотека расширений C...в этом случае получить адрес объекта тривиально, поскольку объекты Python всегда передаются как указатели C.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top