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.