W Pythonie (2 i 3). Ilekroć używamy wycinania list, zwraca nowy obiekt, np .:
l1 = [1,2,3,4]
print(id(l1))
l2 = l1[:]
print(id(l2))
Wynik
>>> 140344378384464
>>> 140344378387272
Jeśli to samo powtarza się z krotką, zwracany jest ten sam obiekt, np .:
t1 = (1,2,3,4)
t2 = t1[:]
print(id(t1))
print(id(t2))
Wynik
>>> 140344379214896
>>> 140344379214896
Byłoby wspaniale, gdyby ktoś mógł wyjaśnić, dlaczego tak się dzieje, przez całe moje doświadczenie w Pythonie miałem wrażenie, że pusty plasterek zwraca nowy obiekt.
Rozumiem, że zwraca ten sam obiekt, ponieważ krotki są niezmienne i nie ma sensu tworzyć nowej kopii. Ale znowu, nigdzie nie wspomniano w dokumentach.
l2 = tuple(iter(l1))
omija optymalizacjęPyTuple_GetSlice
zostało udokumentowane niedokładnie po zobaczeniu twojego pytania. Dokumenty zostały teraz naprawione (był to błąd BPO38557 ).Odpowiedzi:
Implementacje mogą zwracać identyczne instancje dla typów niezmiennych (w CPython możesz czasem zobaczyć podobne optymalizacje dla ciągów i liczb całkowitych). Ponieważ obiekt nie może zostać zmieniony, w kodzie użytkownika nie ma nic, co musiałoby dbać o to, czy zawiera on unikalną instancję, czy tylko inne odniesienie do istniejącej instancji.
Zwarcie można znaleźć w kodzie C tutaj .
Jest to szczegół implementacji, zauważ, że pypy nie robi tego samego.
źródło
a->ob_item
jest(*a).ob_item
, tzn. Pobiera element wywoływanyob_item
z elementuPyTupleObject
, na który wskazuje a, a następnie znak + przechodzi do początku wycinka.To szczegół implementacji. Ponieważ listy są zmienne,
l1[:]
musisz utworzyć kopię, ponieważ nie spodziewałbyś się, że zmianyl2
wpłynąl1
.Ponieważ krotka jest niezmienna , nic nie możesz zrobić, aby
t2
wpłynąć na niąt1
w jakikolwiek widoczny sposób, więc kompilator może swobodnie (ale nie musi ) używać tego samego obiektu dlat1
it1[:]
.źródło
W Pythonie 3. *
my_list[:]
jest cukrem składniowym, dlatype(my_list).__getitem__(mylist, slice_object)
którego:slice_object
jest obiektem wycinka zbudowanym zmy_list
atrybutów (długości) i wyrażenia[:]
. Obiekty, które zachowują się w ten sposób, nazywane są subskrybowalnymi w modelu danych Python, patrz tutaj . W przypadku list i krotek__getitem__
jest wbudowany metoda.W CPython oraz dla list i krotek
__getitem__
jest interpretowany przez operację kodu bajtowego,BINARY_SUBSCR
która jest implementowana dla krotek tutaj i dla list tutaj .W przypadku krotek, spacery przez kod widać, że w tym bloku kodu ,
static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item)
powróci odniesienie do tego samegoPyTupleObject
, który dostał jako argumentu wejściowego, jeśli element jest typuPySlice
i analizuje schemat plasterek całego krotki.Teraz sprawdzasz kod
static PyObject * list_subscript(PyListObject* self, PyObject* item)
i przekonujesz się, że niezależnie od wycinka zawsze zwracany jest nowy obiekt listy.źródło
start:stop
wycinek wbudowanego typu, w tymtup[:]
, nie przechodziBINARY_SUBSCR
. Rozszerzone krojeniestart:stop:step
przechodzi jednak przez subskrypcję.Nie jestem tego pewien, ale wydaje się, że Python zapewnia nowy wskaźnik do tego samego obiektu, aby uniknąć kopiowania, ponieważ krotki są identyczne (a ponieważ obiekt jest krotką, jest niezmienny).
źródło