2016-11-26 10 views
38

Czy ktoś może wyjaśnić następujące rzeczy?Czy istnieje różnica między [] a list() podczas korzystania z id()?

Dlaczego identyfikator jest taki sam, ale listy są różne?

>>> [] is [] 
False 
>>> id([]) == id([]) 
True 

Czy są różnice w tworzeniu listy?

>>> id(list()) == id(list()) 
False 
>>> id([]) == id([]) 
True 

Dlaczego tak się dzieje? Dostaję dwie różne listy. Dlaczego nie tylko jeden, lub trzy lub więcej?

>>> [].__repr__ 
<method-wrapper '__repr__' of list object at 0x7fd2be868128> 
>>> [].__repr__ 
<method-wrapper '__repr__' of list object at 0x7fd2be868170> 
>>> [].__repr__ 
<method-wrapper '__repr__' of list object at 0x7fd2be868128> 
>>> [].__repr__ 
<method-wrapper '__repr__' of list object at 0x7fd2be868170> 

Odpowiedz

76

Użyłeś id() złego. id([]) przyjmuje identyfikator pamięci obiektu, który jest odrzucony natychmiast. W końcu nic już nie ma na ten temat żadnego odniesienia, gdy zrobi się z nim id(). Więc następnym razem, gdy użyjesz id([]), Python widzi okazję do ponownego użycia pamięci i zobacz, że te adresy są rzeczywiście takie same.

Jest to jednak szczegół implementacji, na który nie można polegać i nie zawsze będzie można ponownie użyć adresu pamięci.

Należy zauważyć, że id() wartości mają unikalne do życia obiektu, patrz documentation:

ta jest liczbą całkowitą, która gwarantuje się wyjątkowe i stałe dla danego obiektu podczas jego użytkowania. Dwa obiekty z nienakładającymi się okresami życia mogą mieć tę samą wartość id().

(Pogrubione podkreślenie moje).

To id(list()) nie można ponownie wykorzystać miejsce w pamięci jest prawdopodobnie z powodu dodatkowych mutacji sterty spowodowanych przez popychanie bieżącej ramki na stosie, aby wywołać funkcję, następnie pojawiały się ponownie, gdy list() powraca połączeń.

Zarówno [], jak i list() tworzą nowy obiekt z pustą listą nowy; ale trzeba najpierw stworzyć odniesień do tych oddzielnych listach (tutaj a i b):

>>> a, b = [], [] 
>>> a is b 
False 
>>> id(a) == id(b) 
False 
>>> a, b = list(), list() 
>>> a is b 
False 
>>> id(a) == id(b) 
False 

To samo dzieje się, kiedy stosowane [].__repr__. Interaktywny interpreter Pythona ma specjalną nazwę globalnej _, które można wykorzystać do odniesienia ostatni wynik Produkcja:

>>> [].__repr__ 
<method-wrapper '__repr__' of list object at 0x10e011608> 
>>> _ 
<method-wrapper '__repr__' of list object at 0x10e011608> 

To stwarza dodatkowe odniesienie, więc metody __repr__, a co za tym idzie, pusta lista została utworzona dla tego, są nadal uważane za aktywne. Lokalizacja pamięci nie jest zwalniana i niedostępna dla następnej utworzonej listy.

Po ponownym uruchomieniu [].__repr__, Python wiąże teraz _ z tym nowym obiektem metody. Nagle poprzednia metoda __repr__ nie jest już przywoływana przez nic i może zostać zwolniona, podobnie jak obiekt listy.

Trzeci raz wykonać [].__repr__ pierwsze miejsce w pamięci jest znowu dostępny do ponownego użycia, więc Python właśnie to robi:

>>> [].__repr__ # create a new method 
<method-wrapper '__repr__' of list object at 0x10e00cb08> 
>>> _   # now _ points to the new method 
<method-wrapper '__repr__' of list object at 0x10e00cb08> 
>>> [].__repr__ # so the old address can be reused 
<method-wrapper '__repr__' of list object at 0x10e011608> 

nigdy utworzyć więcej niż dwie listy; poprzednia (wciąż przywoływana przez _) i aktualna. Jeśli chcesz zobaczyć więcej lokalizacji pamięci, użyj zmiennych, aby dodać kolejne odniesienie.

Powiązane problemy