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 życieoverlap/not overlap
) w tym kontekście?Możesz ponownie zaimplementować domyślną repr w ten sposób:
źródło
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
źródło
id()
@JLTJest tutaj kilka problemów, które nie zostały uwzględnione w żadnej z innych odpowiedzi.
Pierwszy,
id
zwraca tylko: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 rodzajeid
, 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łorepr
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 ten0x2aba1c0cf890
ciąg zamiast liczby46978822895760
, będziesz musiał sam go sformatować. Pod kołdrą, wierzęobject.__repr__
ostatecznie używającprintf
„s%p
formatu, które nie mają z Pythona ... ale zawsze można to zrobić:* 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 - along
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ę jestFoo
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
fromctypes
.Wreszcie pojawiło się kilka innych odpowiedzi
ctypes.addressof
. To nie ma tutaj znaczenia. Działa to tylko dlactypes
obiektów takich jakc_int32
(i może kilku obiektów podobnych do bufora pamięci, takich jak te dostarczane przeznumpy
). I nawet tam nie podaje adresuc_int32
wartości, ale adres poziomu C,int32
któryc_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.źródło
id
- w tym używanie ich do przechowywania zmiennych wartości wseen
zestawie lubcache
dyktandzie - nie zależą w żaden sposób odid
bycia wskaźnikiem ani w żaden sposób powiązane zrepr
. 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 samid
fo, niezależnie od tego, czy jest to adres, czy nie. Na przykład w PyPyid
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. Ponadtoid(a) != addressof(a)
. To jest w CPythonie, nie wiem nic więcej.źródło
Dzięki ctypes możesz osiągnąć to samo dzięki
Dokumentacja:
Zauważ, że w CPythonie obecnie
id(a) == ctypes.addressof(a)
, alectypes.addressof
powinien zwrócić rzeczywisty adres dla każdej implementacji Pythona, jeśliEdycja : dodano informacje o niezależności ctypów od tłumacza
źródło
TypeError: invalid type
pojawia się, gdy spróbuję go z Pythonem 3.4.Możesz dostać coś odpowiedniego do tego celu dzięki:
źródło
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:
konwersja ciągów nie wpływa również na lokalizację w pamięci:
źródło
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.
źródło
ctypes
zestawu narzędzi z Biblioteki standardowej. W takim przypadku możesz robić różne rzeczy z adresem :)