Відповіді:
У посібнику Python слід сказати про id()
:
Поверніть "ідентичність" об'єкта. Це ціле число (або довге ціле число), яке гарантовано є унікальним і постійним для цього об'єкта протягом його життя. Два об'єкти з періодами, що не перекриваються, можуть мати однакове значення id (). (Примітка щодо реалізації: це адреса об'єкта.)
Отже, у CPython це буде адреса об’єкта. Однак жодної гарантії для будь-якого іншого перекладача Python немає.
Зауважте, що якщо ви пишете розширення C, ви маєте повний доступ до внутрішнього інтерпретатора Python, включаючи доступ безпосередньо до адрес об'єктів.
lifetime
(і що це означає протягом життя overlap/not overlap
) у цьому контексті?
Ви можете повторно виконати повторне перевидання за замовчуванням таким чином:
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
return object.__repr__(self)
або навіть просто робити object.__repr__(obj)
коли завгодно, а не робити новий клас
__repr__ = object.__repr__
, і це не так вже й нерозумно, оскільки існує безліч ситуацій, коли це не працює, наприклад, переосмислена __getattribute__
чи не-CPython реалізація, коли ідентифікатор не є місце пам'яті. Він також не z-fill, тому вам доведеться розібратися, якщо система 64-бітна, і додайте нулі за необхідності.
Просто використовуйте
id(object)
id()
@JLT
Тут є кілька питань, на які не висвітлено жодна з інших відповідей.
По-перше, id
лише повертає:
"ідентичність" об'єкта. Це ціле число (або довге ціле число), яке гарантовано буде унікальним і постійним для цього об'єкта протягом його життя. Два об'єкти з періодами життя, що не перекриваються, можуть мати однакове
id()
значення.
У CPython це трапляється як вказівник на те, PyObject
що представляє об'єкт в інтерпретаторі, і це те саме, що object.__repr__
відображається. Але це лише деталізація реалізації CPython, а не те, що стосується Python взагалі. Jython не займається покажчиками, він займається посиланнями на Java (що, звичайно, JVM представляє як покажчики, але ви їх не можете бачити - і цього не хочете, оскільки GC може переміщувати їх). PyPy дозволяє різним типам мати різні види id
, але найзагальнішим є лише індекс у таблиці об’єктів, яких ви викликалиid
на, що, очевидно, не буде вказівником. Я не впевнений у 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, це int
. У 2.x, int
якщо це достатньо велике розміщення вказівника, що може бути не через підписані проблеми з номером на деяких платформах, і long
інше.
Чи можна зробити щось із цими вказівниками, крім того, щоб роздрукувати їх? Звичайно (знову ж таки, припускаючи, що ви дбаєте лише про CPython).
Всі функції API 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
об'єкт.
id
включаючи їх використання для зберігання змінних значень у seen
множині чи cache
диктаті - не залежать від будь-якого способу від того, id
що є вказівником, або пов’язані будь-яким чином з repr
. Саме тому такий код працює у всіх реалізаціях Python, а не лише у CPython.
id
для цього, але я маю на увазі, що навіть у Java ви можете отримати адресу об'єкта, здається дивним, що немає ніякого шляху в (C) Python, оскільки у нього є фактично стабільний gc, який не переміщуватиме об'єкти, тому адреса залишається такою ж
id
fo об'єкт, будь то адреса чи ні. Наприклад, у PyPy id
все ще так само корисно, як і ключ у CPython, хоча зазвичай це лише індекс в якусь приховану таблицю в реалізації, але вказівник буде марний, тому що (як Java) об’єкт можна перемістити в пам'ять.
id
об'єкт є вказівником на розташування об'єкта в пам'яті. Отже, якщо у вас є якесь значення для значення вказівника (чого ви майже ніколи не робите, як це також пояснено у відповіді) у специфічному для CPython коду, є спосіб отримати його документально підтвердженим та гарантовано працюючим.
Щойно у відповідь на Торстена, я не зміг зателефонувати 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
З типом ви можете домогтися того ж самого
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Документація:
addressof(C instance) -> integer
Поверніть адресу внутрішнього буфера екземпляра C
Зауважте, що в CPython в даний час id(a) == ctypes.addressof(a)
, але ctypes.addressof
повинен повернути реальну адресу для кожної реалізації Python, якщо
Редагувати : додана інформація про незалежність інтерпретаторів типів
TypeError: invalid type
коли я пробую його з Python 3.4.
Ви можете отримати щось підходяще для цієї мети за допомогою:
id(self)
Я знаю, що це старе питання, але якщо ти все ще програмуєш, в 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>'
Хоча це правда, що id(object)
отримує адресу об’єкта в реалізації за замовчуванням CPython, це, як правило, марно ... ви не можете нічого зробити з адресою з чистого коду Python.
Єдиний раз, коли ви насправді зможете скористатись адресою, це бібліотека розширень C ... в цьому випадку тривіально отримати адресу об’єкта, оскільки об’єкти Python завжди передаються навколо як покажчики C.
ctypes
інструментарій у Стандартній бібліотеці. У такому випадку ви можете робити всілякі речі з адресою :)