Jak działa przypisanie z wycinkiem listy w Pythonie?


100

Dokument Pythona mówi, że cięcie listy zwraca nową listę.
Teraz, jeśli zwracana jest „nowa” lista, mam następujące pytania związane z „Przydziałem do plasterków”

a = [1, 2, 3]
a[0:2] = [4, 5]
print a

Teraz wynik będzie następujący:

[4, 5, 3] 
  1. Jak coś, co coś zwraca, może pojawić się po lewej stronie ekspresji?
  2. Tak, przeczytałem dokumentację i jest tam napisane, że jest to możliwe, skoro cięcie listy zwraca „nową” listę, dlaczego oryginalna lista jest modyfikowana? Nie jestem w stanie zrozumieć stojącej za tym mechaniki.

@Mark Longair przepraszam, myślałem, że tylko kod ma być sformatowany, a nie dane wyjściowe
Kartik Anand


7
Czy rozumiesz, co a[0] = 4by zrobił?
Josh Lee

1
Przypisanie @KartikAnand Slice jest specjalnym scenariuszem, w którym nowa lista nie jest tworzona. Nie ma sensu tworzenie obiektu bez powiązania nazwy po lewej stronie an =, więc zamiast odrzucać to jako nieprawidłową składnię, Python zamienia go w coś bardziej podobnego do tego, czego można się spodziewać. Ponieważ Python nie ma odniesień, nie działałoby, gdyby wycinek zmienił oryginalną listę. Otrzymasz kopię. Jeśli podałeś więcej informacji na temat swojej aplikacji, być może będziemy mogli lepiej pomóc Ci robić rzeczy w sposób „pythonowy”. :)
Casey Kuball

1
@Darthfett Nie pracuję teraz nad żadną aplikacją, raczej uczę się Pythona, zanim zacznę brudzić sobie ręce :)
Kartik Anand

Odpowiedzi:


114

Mylisz dwie różne operacje, które używają bardzo podobnej składni:

1) krojenie:

b = a[0:2]

To tworzy kopię wycinka ai przypisuje go do b.

2) przypisanie plasterków:

a[0:2] = b

To zastępuje się kawałek az treścią b.

Chociaż składnia jest podobna (tak sobie wyobrażam!), Są to dwie różne operacje.


4
Oto moja wątpliwość, w drugim przypadku dlaczego nie jest to kawałek nowej listy?
Kartik Anand

11
@KartikAnand Ponieważ tak nie jest. Nie to określa język.
Marcin

Żeby było jasne, „bierze kawałek” naprawdę oznacza „zrób kopię kawałka”, z którego pochodzi część zamieszania.
Mark Ransom

2
@KartikAnand: Zasadniczo tak. Tłumacz wie, który jest który, i odpowiednio je obsługuje.
NPE

1
@Dubslow: możesz to zrobić za pomocą modułu itertools . W Twoim przypadku korzystania z funkcji islice , z start=1, stop=None. Pozwoli to uniknąć jakichkolwiek kopii i wykorzysta leniwą ocenę (w twoim przypadku leniwy dostęp do oryginalnej listy).
Spiros

66

Kiedy określasz apo lewej stronie =operatora, używasz normalnego przypisania Pythona , które zmienia nazwę aw bieżącym kontekście, aby wskazywała na nową wartość. Nie zmienia to poprzedniej wartości, na którą awskazywano.

Określając a[0:2]po lewej stronie =operatora, mówisz Pythonowi, że chcesz użyć Slice Assignment . Przypisanie plasterka to specjalna składnia dla list, w której można wstawiać, usuwać lub zamieniać zawartość listy:

Wstawianie :

>>> a = [1, 2, 3]
>>> a[0:0] = [-3, -2, -1, 0]
>>> a
[-3, -2, -1, 0, 1, 2, 3]

Usunięcie :

>>> a
[-3, -2, -1, 0, 1, 2, 3]
>>> a[2:4] = []
>>> a
[-3, -2, 1, 2, 3]

Zamiennik :

>>> a
[-3, -2, 1, 2, 3]
>>> a[:] = [1, 2, 3]
>>> a
[1, 2, 3]

Uwaga:

Długość wycinka może różnić się od długości przypisanej sekwencji, zmieniając w ten sposób długość sekwencji docelowej, jeśli pozwala na to sekwencja docelowa. - źródło

Slice Assignment zapewnia podobną funkcję do Tuple Unpacking . Na przykład a[0:1] = [4, 5]jest równoważne z:

# Tuple Unpacking
a[0], a[1] = [4, 5]

Za pomocą funkcji Rozpakowywanie krotek można modyfikować listy niesekwencyjne:

>>> a
[4, 5, 3]
>>> a[-1], a[0] = [7, 3]
>>> a
[3, 5, 7]

Jednak rozpakowanie krotki ogranicza się do wymiany, ponieważ nie można wstawiać ani usuwać elementów.

Przed i po tych wszystkich operacjach ajest ta sama dokładna lista. Python po prostu zapewnia ładny cukier składniowy do modyfikowania listy w miejscu.


6
Podobnie, ale nie identycznie, ponieważ możesz mieć nierówną liczbę elementów po lewej i prawej stronie.
Mark Ransom

@MarkRansom To doskonała uwaga, dodałem więcej informacji, aby to było oczywiste.
Casey Kuball

2
Jest a[:] = some_listodpowiednikiem a = some_list[:]lub a = some_list?
jadkik94

2
@ jadkik94 Ani. a[:] = some_listustawia każdy element abędzie tych some_list. Wykonanie któregokolwiek z wymienionych, zmieniłoby to, co ajest. Na przykład: a = [1, 2, 3] b = a a[:] = [4, 5, 6] a is b. Ostatnia linia byłaby False, gdyby zmieniła awartość, zamiast ją modyfikować.
Casey Kuball

@Darthfett Ciekawe, znalazłem inaczej :) Dzięki.
jadkik94

25

Natknąłem się wcześniej na to samo pytanie i jest ono związane ze specyfikacją języka. Zgodnie z instrukcjami przypisania ,

  1. Jeśli lewa strona przypisania to subskrypcja, Python wywoła __setitem__ten obiekt. a[i] = xjest równoważne a.__setitem__(i, x).

  2. Jeśli lewa strona przypisania to slice, Python również wywoła __setitem__, ale z innymi argumentami: a[1:4]=[1,2,3]jest równoważne a.__setitem__(slice(1,4,None), [1,2,3])

Dlatego wycinek listy po lewej stronie '=' zachowuje się inaczej.


4

Przecinając po lewej stronie operacji przypisywania, określasz, do których elementów chcesz przypisać.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.