2009-09-08 16 views
83

Załóżmy, że mam identyfikator obiektu Python, który pobrałem wykonując id(thing). Jak ponownie znaleźć thing przez podany numer identyfikacyjny?Pobierz obiekt według id()?

+0

Jestem ciekawy: dlaczego chcesz to zrobić? Jaki jest twój cel? –

+1

@Craig McQueen: http: // stackoverflow.com/questions/1400295/python-class-for-pickle-and-copy-persistent-object –

+0

Nie mogłem ponownie znaleźć źródła tego, ale myślałem, że to, co jest zwracane przez id(), jest tym, czego chce konkretna dystrybucja że jest to. Zmieniony CPython może teraz zwracać teraz adres podobny do pamięci, ale inne dystrybucje mogą zwracać różne typy obiektów lub int, które nie są wskaźnikami pamięci. Byłoby miło, gdyby istniała wbudowana funkcja do uzyskania obiektu przez to, co jest zwracane przez id(). Chociaż inne przypadki użycia uporczywości są trudne do wyobrażenia. Również, chociaż * zmienna, jak C wydaje się mieć sens; Uwielbiam Pythona za brak sztuczek interpunkcyjnych, jak większość innych języków. – DevPlayer

Odpowiedz

26

Pewnie warto rozważyć wdrożenie to w inny sposób. Czy znasz moduł weakref?

(Edytowane) Python weakref module umożliwia zachowanie odniesień, odniesień słownikowych i serwerów proxy do obiektów bez liczenia odwołań w liczniku odwołań. Są jak dowiązania symboliczne.

+4

Czasami nie można utworzyć słabego odwołania do obiektu, np .: TypeError: nie można utworzyć słabego odwołania do obiektu "lxml.etree._Element". – darkk

32

Możesz użyć modułu gc, aby pobrać wszystkie obiekty aktualnie śledzone przez moduł do zbierania śmieci Pythona.

import gc 

def objects_by_id(id_): 
    for obj in gc.get_objects(): 
     if id(obj) == id_: 
      return obj 
    raise Exception("No found") 
+5

To ma problem z aliasingiem: identyfikator uzyskany w dowolnym punkcie w przeszłości może teraz odnosić się do innego obiektu. – chaos

+6

Dopóki zachowujesz odniesienie do obiektu, tak się nie stanie. Tak samo, to na ogół zły pomysł. –

+0

Zgadzam się z wieloma innymi komentatorami: nie rób tego. Stwórz własny słownik przedmiotów. –

34

Krótka odpowiedź, nie możesz.

Długa odpowiedź, możesz zachować dyktat do mapowania identyfikatorów do obiektów lub sprawdzić ID poprzez wyczerpujące wyszukiwanie gc.get_objects(), ale spowoduje to jeden z dwóch problemów: albo odniesienie do dyktatu utrzyma obiekt przy życiu i zapobiegnie GC lub (jeśli jest to dyktatura WeakValue lub używasz gc.get_objects()), identyfikator może zostać zwolniony i ponownie użyty dla zupełnie innego obiektu.

Zasadniczo, jeśli próbujesz to zrobić, prawdopodobnie musisz zrobić coś inaczej.

+0

Mam zamiar odrzucić referencję id w obiekcie '__del__', czy myślisz, że to się sprawi, że rzeczy się nie zepsują? –

+6

+1: Zgadzam się: Nie rób tego. Po prostu stwórz odpowiedni słownik obiektów z odpowiednimi klawiszami - będziesz o wiele szczęśliwszy. –

+1

@ cool-RR: Tak, powinieneś być z tym bezpieczny. – chaos

7

Wystarczy wspomnieć o tym module dla kompletności. This code by Bill Bumgarner zawiera rozszerzenie C, aby zrobić to, co chcesz, bez pętli w każdym istniejącym obiekcie.

Kod funkcji jest dość prosty. Każdy obiekt Pythona jest reprezentowany w C przez wskaźnik do a PyObject struct. Ponieważto po prostu adres pamięci tej struktury, możemy pobrać obiekt Pythona przez potraktowanie x jako wskaźnika do PyObject, a następnie wywołanie Py_INCREF w celu poinformowania śmieciarza, że ​​tworzymy nowe odniesienie do obiektu.

static PyObject * 
di_di(PyObject *self, PyObject *args) 
{ 
    PyObject *obj; 
    if (!PyArg_ParseTuple(args, "l:di", &obj)) 
     return NULL; 

    Py_INCREF(obj); 
    return obj; 
} 

Jeśli oryginalny obiekt już nie istnieje, wynik jest niezdefiniowany. Może się zawiesić, ale może również zwrócić odniesienie do nowego obiektu, który zajął miejsce starego w pamięci.

116

Jeśli obiekt jest nadal istnieje, można to zrobić przez ctypes:

import ctypes 
a = "hello world" 
print ctypes.cast(id(a), ctypes.py_object).value 

wyjściowa:

hello world 

Jeśli nie wiemy, czy obiekt jest nadal istnieje, to jest przepis na niezdefiniowane zachowanie i dziwne wypadki lub gorzej, więc bądź ostrożny.

+9

W CPython, dzisiaj, w każdym razie. : ^) – DSM

+4

Ten jest idealną odpowiedzią! –

+8

@HamidFzM Nie, niezupełnie. Jeśli mam identyfikator, może nawet nie wiem, czy obiekt nadal istnieje, czy nie. – glglgl

0

to zrobi:

a = 0 
id_a = id(a) 
variables = {**locals(), **globals()} 
for var in variables: 
    exec('var_id=id(%s)'%var) 
    if var_id == id_a: 
     exec('the_variable=%s'%var) 
print(the_variable) 
print(id(the_variable)) 

ale sugeruję wdrożenie bardziej przyzwoity sposób.

Powiązane problemy