Come funziona l'assegnazione con la fetta di elenco Python?


100

Il documento Python dice che affettare una lista restituisce una nuova lista.
Ora, se viene restituito un "nuovo" elenco, ho le seguenti domande relative a "Assegnazione a sezioni"

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

Ora l'output sarebbe:

[4, 5, 3] 
  1. Come può qualcosa che sta restituendo qualcosa venire sul lato sinistro dell'espressione?
  2. Sì, ho letto i documenti e mi si dice che è possibile, ora che l'affettamento di un elenco restituisce un elenco "nuovo", perché l'elenco originale viene modificato? Non sono in grado di capire i meccanismi che stanno dietro.

@Mark Longair mi dispiace, pensavo che solo il codice dovesse essere formattato, non l'output
Kartik Anand


7
Capisci cosa a[0] = 4farebbe?
Josh Lee

1
L'assegnazione @KartikAnand Slice è uno scenario speciale in cui non viene creato un nuovo elenco. Non ha senso creare un oggetto senza un'associazione del nome sul lato sinistro di un =, quindi invece di scartarlo come sintassi non valida, Python lo trasforma in qualcosa di più simile a quello che potresti aspettarti. Poiché python non ha riferimenti, non funzionerebbe se il risultato di una fetta cambiasse l'elenco originale. Ottieni una copia. Se hai fornito maggiori informazioni sulla tua applicazione, potremmo essere in grado di aiutarti meglio a fare le cose in modo "pitonico". :)
Casey Kuball

1
@Darthfett Non sto lavorando su nessuna applicazione in questo momento, piuttosto sto insegnando a me stesso Python prima di iniziare a sporcarmi le mani :)
Kartik Anand

Risposte:


114

Stai confondendo due operazioni distinte che utilizzano una sintassi molto simile:

1) affettare:

b = a[0:2]

Questo crea una copia della sezione di ae la assegna a b.

2) assegnazione slice:

a[0:2] = b

Questo sostituisce la fetta di acon il contenuto di b.

Sebbene la sintassi sia simile (immagino in base alla progettazione!), Queste sono due operazioni diverse.


4
Questo è il mio dubbio, nel secondo caso, perché la fetta di una, una nuova lista non è ??
Kartik Anand

11
@KartikAnand Perché non lo è. Non è quello che specifica la lingua.
Marcin

Per essere chiari, "prende una fetta di" significa "fare una copia di una fetta di" da cui proviene parte della confusione.
Mark Ransom

2
@KartikAnand: Fondamentalmente, sì. L'interprete sa quale è quale e li gestisce in modo appropriato.
NPE

1
@Dubslow: puoi farlo usando il modulo itertools . Per il vostro caso, utilizzare la funzione di iSlice , con start=1, stop=None. Ciò eviterà qualsiasi copia e utilizzerà una valutazione lenta (nel tuo caso un accesso pigro all'elenco originale).
Spiros

66

Quando specifichi asul lato sinistro =dell'operatore, stai usando l' assegnazione normale di Python , che cambia il nome anel contesto corrente in modo che punti al nuovo valore. Ciò non modifica il valore precedente a cui apuntava.

Specificando a[0:2]sul lato sinistro =dell'operatore, stai dicendo a Python che vuoi usare Slice Assignment . Slice Assignment è una sintassi speciale per gli elenchi, in cui è possibile inserire, eliminare o sostituire i contenuti da un elenco:

Inserimento :

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

Cancellazione :

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

Sostituzione :

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

Nota:

La lunghezza della sezione può essere diversa dalla lunghezza della sequenza assegnata, cambiando così la lunghezza della sequenza di destinazione, se la sequenza di destinazione lo consente. - fonte

Slice Assignment fornisce una funzione simile a Tuple Unpacking . Ad esempio, a[0:1] = [4, 5]è equivalente a:

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

Con Tuple Unpacking, puoi modificare elenchi non sequenziali:

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

Tuttavia, il disimballaggio della tupla è limitato alla sostituzione, poiché non è possibile inserire o rimuovere elementi.

Prima e dopo tutte queste operazioni, aè lo stesso elenco esatto. Python fornisce semplicemente un piacevole zucchero sintattico per modificare un elenco sul posto.


6
Simile ma non identico, poiché puoi avere un numero di elementi disuguale a sinistra ea destra.
Mark Ransom

@MarkRansom Questo è un punto eccellente, ho aggiunto ulteriori informazioni per renderlo ovvio.
Casey Kuball

2
È a[:] = some_listequivalente a a = some_list[:]o a = some_list?
jadkik94

2
@ jadkik94 Nessuno dei due. a[:] = some_listimposta ogni elemento di aper essere quelli di some_list. Fare uno di quelli che hai menzionato cambierebbe ciò che aè. Ad esempio: a = [1, 2, 3] b = a a[:] = [4, 5, 6] a is b. L'ultima riga sarebbe False se cambiasse ail valore, invece di modificarlo.
Casey Kuball

@Darthfett Interessante, avevo trovato diversamente :) Grazie.
jadkik94

25

Mi sono imbattuto nella stessa domanda prima ed è correlata alla specifica della lingua. Secondo le dichiarazioni di assegnazione ,

  1. Se il lato sinistro dell'assegnazione è la sottoscrizione, Python chiamerà __setitem__quell'oggetto. a[i] = xè equivalente a a.__setitem__(i, x).

  2. Se il lato sinistro dell'assegnazione è slice, anche Python chiamerà __setitem__, ma con argomenti diversi: a[1:4]=[1,2,3]è equivalente a a.__setitem__(slice(1,4,None), [1,2,3])

Ecco perché list slice sul lato sinistro di "=" si comporta in modo diverso.


4

Affettando sul lato sinistro di un'operazione di assegnazione, stai specificando gli elementi a cui assegnare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.