Odpowiedzi:
Podręcznik Pythona mówi o tym id()
:
Zwróć „tożsamość” obiektu. Jest to liczba całkowita (lub długa liczba całkowita), która na pewno będzie unikalna i stała dla tego obiektu podczas jego życia. Dwa obiekty z nienakładającymi się okresami istnienia mogą mieć tę samą wartość id (). (Uwaga implementacyjna: to jest adres obiektu).
Więc w CPythonie będzie to adres obiektu. Nie ma takiej gwarancji dla żadnego innego interpretera Pythona.
Zauważ, że jeśli piszesz rozszerzenie C, masz pełny dostęp do wewnętrznych elementów interpretera Pythona, w tym bezpośredni dostęp do adresów obiektów.
lifetime
(i co oznacza przez całe życie overlap/not overlap
) w tym kontekście?
Możesz ponownie zaimplementować domyślną repr w ten sposób:
def __repr__(self):
return '<%s.%s object at %s>' % (
self.__class__.__module__,
self.__class__.__name__,
hex(id(self))
)
return object.__repr__(self)
a nawet zrobić, object.__repr__(obj)
kiedy tylko potrzebujesz, zamiast tworzyć nowe zajęcia
__repr__ = object.__repr__
i nie jest aż tak głupi dowód, ponieważ istnieje wiele sytuacji, w których to nie działa, np. __getattribute__
Implementacja z przesłonięciem lub inna niż CPython, gdzie id nie jest lokalizacja pamięci. Nie wypełnia również w Z, więc musisz sprawdzić, czy system jest 64-bitowy i dodać zera w razie potrzeby.
Po prostu użyj
id(object)
id()
@JLT
Jest tutaj kilka problemów, które nie zostały uwzględnione w żadnej z innych odpowiedzi.
Pierwszy, id
zwraca tylko:
„tożsamość” przedmiotu. Jest to liczba całkowita (lub długa liczba całkowita), która jest unikalna i stała dla tego obiektu w czasie jego życia. Dwa obiekty z nienakładającymi się okresami istnienia mogą mieć tę samą
id()
wartość.
W CPythonie jest to wskaźnik do tego, PyObject
który reprezentuje obiekt w interprecie, co jest tym samym, coobject.__repr__
wyświetla. Ale to tylko szczegół implementacji CPythona, a nie coś, co jest prawdą w Pythonie w ogóle. Jython nie zajmuje się wskaźnikami, zajmuje się odwołaniami do języka Java (które JVM oczywiście prawdopodobnie reprezentuje jako wskaźniki, ale nie możesz ich zobaczyć - i nie chcesz, ponieważ GC może je przenosić). PyPy pozwala różnym typom mieć różne rodzaje id
, ale najbardziej ogólny jest po prostu indeksem do tabeli obiektów, które wywołałeśid
on, który oczywiście nie będzie wskaźnikiem. Nie jestem pewien co do IronPythona, ale podejrzewam, że pod tym względem bardziej przypomina Jython niż CPython. Tak więc w większości implementacji Pythona nie ma sposobu, aby uzyskać to, co się w nim pojawiło repr
i nie ma sensu, jeśli to zrobisz.
Ale co, jeśli zależy ci tylko na CPythonie? W końcu to dość powszechny przypadek.
Cóż, po pierwsze, możesz zauważyć, że id
jest to liczba całkowita; * jeśli chcesz ten 0x2aba1c0cf890
ciąg zamiast liczby 46978822895760
, będziesz musiał sam go sformatować. Pod kołdrą, wierzę object.__repr__
ostatecznie używając printf
„s %p
formatu, które nie mają z Pythona ... ale zawsze można to zrobić:
format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')
* W wersji 3.x jest to plik int
. W wersji 2.x jest to, int
czy jest wystarczająco duży, aby pomieścić wskaźnik - co może nie wynikać z problemów z liczbą ze znakiem na niektórych platformach - a long
poza tym.
Czy jest coś, co możesz zrobić z tymi wskazówkami oprócz ich wydrukowania? Jasne (ponownie, zakładając, że obchodzi Cię tylko CPython).
Wszystkie funkcje C API pobierają wskaźnik do PyObject
lub pokrewnego typu. W przypadku tych pokrewnych typów możesz po prostu wywołać, PyFoo_Check
aby upewnić się, że to naprawdę jest Foo
obiekt, a następnie wykonać rzut za pomocą (PyFoo *)p
. Tak więc, jeśli piszesz rozszerzenie C, id
jest dokładnie tym, czego potrzebujesz.
A jeśli piszesz czysty kod w Pythonie? Możesz wywołać dokładnie te same funkcje za pomocą pythonapi
from ctypes
.
Wreszcie pojawiło się kilka innych odpowiedzi ctypes.addressof
. To nie ma tutaj znaczenia. Działa to tylko dla ctypes
obiektów takich jak c_int32
(i może kilku obiektów podobnych do bufora pamięci, takich jak te dostarczane przez numpy
). I nawet tam nie podaje adresu c_int32
wartości, ale adres poziomu C, int32
który c_int32
zawija.
Biorąc to pod uwagę, najczęściej, jeśli naprawdę myślisz, że potrzebujesz adresu czegoś, nie chciałeś natywnego obiektu Pythona na pierwszym miejscu, chciałeś ctypes
obiektu.
id
- w tym używanie ich do przechowywania zmiennych wartości w seen
zestawie lub cache
dyktandzie - nie zależą w żaden sposób od id
bycia wskaźnikiem ani w żaden sposób powiązane z repr
. Właśnie dlatego taki kod działa we wszystkich implementacjach Pythona, zamiast działać tylko w CPythonie.
id
do tego, ale mam na myśli, że nadal nawet w Javie można uzyskać adres obiektu, wydaje się dziwne, że w (C) Pythonie nie ma sposobu, ponieważ ten ma faktycznie stabilne gc, które nie przenosi obiektów, więc adres pozostaje taki sam
id
fo, niezależnie od tego, czy jest to adres, czy nie. Na przykład w PyPy id
jest nadal tak samo przydatny jak klucz w CPythonie, mimo że zwykle jest to tylko indeks do jakiejś ukrytej tabeli w implementacji, ale wskaźnik byłby bezużyteczny, ponieważ (podobnie jak Java) obiekt można przenieść pamięć.
id
obiekt jest wskaźnikiem do lokalizacji obiektu w pamięci. Tak więc, jeśli masz jakiekolwiek zastosowanie dla wartości wskaźnika (czego prawie nigdy nie robisz, jak również wyjaśniono w odpowiedzi) w kodzie specyficznym dla CPythona, istnieje sposób, aby uzyskać udokumentowaną i gwarantowaną pracę.
W odpowiedzi na Torstena nie mogłem wywołać addressof()
zwykłego obiektu Pythona. Ponadto id(a) != addressof(a)
. To jest w CPythonie, nie wiem nic więcej.
>>> 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
Dzięki ctypes możesz osiągnąć to samo dzięki
>>> import ctypes
>>> a = (1,2,3)
>>> ctypes.addressof(a)
3077760748L
Dokumentacja:
addressof(C instance) -> integer
Zwróć adres wewnętrznego bufora instancji C.
Zauważ, że w CPythonie obecnie id(a) == ctypes.addressof(a)
, ale ctypes.addressof
powinien zwrócić rzeczywisty adres dla każdej implementacji Pythona, jeśli
Edycja : dodano informacje o niezależności ctypów od tłumacza
TypeError: invalid type
pojawia się, gdy spróbuję go z Pythonem 3.4.
Możesz dostać coś odpowiedniego do tego celu dzięki:
id(self)
Wiem, że to stare pytanie, ale jeśli nadal programujesz, w dzisiejszych czasach w Pythonie 3 ... Odkryłem, że jeśli jest to ciąg znaków, jest na to naprawdę łatwy sposób:
>>> spam.upper
<built-in method upper of str object at 0x1042e4830>
>>> spam.upper()
'YO I NEED HELP!'
>>> id(spam)
4365109296
konwersja ciągów nie wpływa również na lokalizację w pamięci:
>>> spam = {437 : 'passphrase'}
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
>>> str(spam)
"{437: 'passphrase'}"
>>> object.__repr__(spam)
'<dict object at 0x1043313f0>'
Chociaż prawdą jest, że id(object)
pobiera adres obiektu w domyślnej implementacji CPythona, jest to generalnie bezużyteczne ... nie można nic zrobić z adresem z czystego kodu Pythona.
Jedyny przypadek, w którym faktycznie mógłbyś użyć adresu, pochodzi z biblioteki rozszerzeń C ... w takim przypadku uzyskanie adresu obiektu jest trywialne, ponieważ obiekty Pythona są zawsze przekazywane jako wskaźniki C.
ctypes
zestawu narzędzi z Biblioteki standardowej. W takim przypadku możesz robić różne rzeczy z adresem :)