Domanda Comprendere la notazione delle sezioni di Python


Ho bisogno di una buona spiegazione (i riferimenti sono un plus) sulla notazione a slice di Python.

Per me, questa notazione ha bisogno di un po 'di ripresa.

Sembra estremamente potente, ma non ho ancora capito la cosa.


2290
2018-02-03 22:31


origine


risposte:


È davvero semplice:

a[start:end] # items start through end-1
a[start:]    # items start through the rest of the array
a[:end]      # items from the beginning through end-1
a[:]         # a copy of the whole array

C'è anche il step valore, che può essere utilizzato con uno dei precedenti:

a[start:end:step] # start through not past end, by step

Il punto chiave da ricordare è che il :end valore rappresenta il primo valore che è non nella fetta selezionata. Quindi, la differenza tra i due end e start è il numero di elementi selezionati (se step è 1, il valore predefinito).

L'altra caratteristica è quella start o end Forse un negativo numero, il che significa che conta dalla fine dell'array anziché dall'inizio. Così:

a[-1]    # last item in the array
a[-2:]   # last two items in the array
a[:-2]   # everything except the last two items

Allo stesso modo, step può essere un numero negativo:

a[::-1]    # all items in the array, reversed
a[1::-1]   # the first two items, reversed
a[:-3:-1]  # the last two items, reversed
a[-3::-1]  # everything except the last two items, reversed

Python è gentile con il programmatore se ci sono meno oggetti di quelli che chiedi. Ad esempio, se lo chiedi a[:-2] e a contiene solo un elemento, si ottiene una lista vuota invece di un errore. A volte preferiresti l'errore, quindi devi essere consapevole che questo può accadere.


3093
2018-02-03 22:48



Il Tutorial su Python ne parla (scorri un po 'fino ad arrivare alla parte relativa alla divisione).

Il diagramma artistico ASCII è utile anche per ricordare come funzionano le fette:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

Un modo per ricordare come funzionano le fette è pensare agli indici come a indicare fra caratteri, con il bordo sinistro del primo carattere numerato 0. Quindi il bordo destro dell'ultimo carattere di una stringa di n i personaggi hanno indice n.


394
2018-02-03 22:49



Enumerazione delle possibilità consentite dalla grammatica:

>>> seq[:]                # [seq[0],   seq[1],          ..., seq[-1]    ]
>>> seq[low:]             # [seq[low], seq[low+1],      ..., seq[-1]    ]
>>> seq[:high]            # [seq[0],   seq[1],          ..., seq[high-1]]
>>> seq[low:high]         # [seq[low], seq[low+1],      ..., seq[high-1]]
>>> seq[::stride]         # [seq[0],   seq[stride],     ..., seq[-1]    ]
>>> seq[low::stride]      # [seq[low], seq[low+stride], ..., seq[-1]    ]
>>> seq[:high:stride]     # [seq[0],   seq[stride],     ..., seq[high-1]]
>>> seq[low:high:stride]  # [seq[low], seq[low+stride], ..., seq[high-1]]

Certamente se (high-low)%stride != 0, quindi il punto finale sarà leggermente inferiore a high-1.

Se stride è negativo, l'ordine è cambiato un po 'dal momento che stiamo contando:

>>> seq[::-stride]        # [seq[-1],   seq[-1-stride],   ..., seq[0]    ]
>>> seq[high::-stride]    # [seq[high], seq[high-stride], ..., seq[0]    ]
>>> seq[:low:-stride]     # [seq[-1],   seq[-1-stride],   ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]

L'affettamento esteso (con virgole ed ellissi) viene principalmente utilizzato solo da strutture dati speciali (come Numpy); le sequenze di base non li supportano.

>>> class slicee:
...     def __getitem__(self, item):
...         return `item`
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'

310
2018-02-03 23:08



Le risposte sopra non discutono l'assegnazione delle fette:

>>> r=[1,2,3,4]
>>> r[1:1]
[]
>>> r[1:1]=[9,8]
>>> r
[1, 9, 8, 2, 3, 4]
>>> r[1:1]=['blah']
>>> r
[1, 'blah', 9, 8, 2, 3, 4]

Ciò può anche chiarire la differenza tra affettatura e indicizzazione.


199
2018-01-18 21:37



Spiega la notazione delle sezioni di Python

In breve, i due punti (:) nella notazione degli iscritti (subscriptable[subscriptarg]) make notation slice - che ha gli argomenti opzionali, start, stop, step:

sliceable[start:stop:step]

Python slicing è un modo computazionalmente veloce per accedere in modo metodico a parti dei tuoi dati. Secondo me, per essere anche un programmatore Python intermedio, è un aspetto della lingua che è necessario conoscere.

Definizioni importanti

Per cominciare, definiamo alcuni termini:

inizio: l'indice iniziale della fetta, includerà l'elemento in questo indice a meno che non sia uguale a Stop, il valore predefinito è 0, cioè il primo indice. Se è negativo, significa iniziare n articoli dalla fine.

Stop: l'indice finale della fetta, lo fa non includi l'elemento in questo indice, predefinito per la lunghezza della sequenza che viene tagliata, cioè fino alla fine inclusa.

passo: l'importo con il quale l'indice aumenta, il valore predefinito è 1. Se è negativo, stai tagliando sopra l'iterabile al contrario.

Come funziona l'indicizzazione

Puoi fare uno qualsiasi di questi numeri positivi o negativi. Il significato dei numeri positivi è semplice, ma per i numeri negativi, proprio come gli indici in Python, si conta all'indietro dalla fine per inizio e Stope per il passo, decrementi semplicemente il tuo indice. Questo esempio è dal tutorial della documentazione, ma l'ho leggermente modificato per indicare quale elemento in una sequenza fa riferimento a ciascun indice:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5 
  -6  -5  -4  -3  -2  -1

Come funziona il taglio

Per usare la notazione delle sezioni con una sequenza che la supporta, devi includere almeno un punto nelle parentesi quadre che seguono la sequenza (che in realtà implementare il __getitem__ metodo della sequenza, secondo il modello di dati Python.)

La notazione Slice funziona così:

sequence[start:stop:step]

E ricorda che ci sono le impostazioni predefinite per inizio, Stop, e passo, quindi per accedere ai valori predefiniti, basta lasciare fuori l'argomento.

La notazione Slice per ottenere gli ultimi nove elementi da una lista (o qualsiasi altra sequenza che la supporta, come una stringa) è simile alla seguente:

my_list[-9:]

Quando vedo questo, leggo la parte tra parentesi come "9 dalla fine alla fine". (In realtà, lo abbrevia mentalmente come "-9, in")

Spiegazione:

La notazione completa è

my_list[-9:None:None]

e per sostituire i valori predefiniti (in realtà quando step è negativo, stopL'impostazione predefinita è -len(my_list) - 1, così None perché stop significa solo che va a qualsiasi punto finale lo porti a):

my_list[-9:len(my_list):1]

Il colon, :, è ciò che dice a Python che gli stai dando una fetta e non un indice regolare. Ecco perché il modo idiomatico di fare una copia superficiale delle liste in Python 2 è

list_copy = sequence[:]

E chiarirli è con:

del my_list[:]

(Python 3 ottiene un list.copy e list.clear metodo.)

quando step è negativo, il valore predefinito per start e stop modificare

Di default, quando il step l'argomento è vuoto (o None), è assegnato a +1.

Ma è possibile passare un intero negativo e la lista (o la maggior parte degli altri standard affettabili) verrà tagliata dalla fine all'inizio.

Quindi una porzione negativa cambierà i valori predefiniti per start e stop!

Confermando questo nella fonte

Mi piace incoraggiare gli utenti a leggere la fonte e la documentazione. Il codice sorgente per gli oggetti fetta e questa logica si trova qui. Per prima cosa determiniamo se step è negativo:

 step_is_negative = step_sign < 0;

Se è così, il limite inferiore è -1  il che significa che dividiamo fino a includere l'inizio, e il limite superiore è la lunghezza meno 1, il che significa che iniziamo alla fine. (Si noti che la semantica di questo -1 è diverso da un -1 che gli utenti possano passare gli indici in Python indicando l'ultimo elemento.)

if (step_is_negative) {
    lower = PyLong_FromLong(-1L);
    if (lower == NULL)
        goto error;

    upper = PyNumber_Add(length, lower);
    if (upper == NULL)
        goto error;
}

Altrimenti step è positivo, e il limite inferiore sarà zero e il limite superiore (che andremo fino ma non includendo) la lunghezza della lista affettata.

else {
    lower = _PyLong_Zero;
    Py_INCREF(lower);
    upper = length;
    Py_INCREF(upper);
}

Quindi, potremmo aver bisogno di applicare i valori predefiniti per start e stop - il default quindi per start viene calcolato come limite superiore quando step è negativo:

if (self->start == Py_None) {
    start = step_is_negative ? upper : lower;
    Py_INCREF(start);
}

e stop, il limite inferiore:

if (self->stop == Py_None) {
    stop = step_is_negative ? lower : upper;
    Py_INCREF(stop);
}

Dai alle tue fette un nome descrittivo!

Potresti trovare utile separare la formazione della fetta dal passarla al list.__getitem__ metodo (questo è ciò che fanno le parentesi quadre). Anche se non sei nuovo, mantiene il tuo codice più leggibile in modo che altri che potrebbero dover leggere il tuo codice possano capire più facilmente cosa stai facendo.

Tuttavia, non puoi semplicemente assegnare alcuni numeri interi separati da due punti a una variabile. Devi usare l'oggetto fetta:

last_nine_slice = slice(-9, None)

Il secondo argomento, None, è richiesto, in modo che il primo argomento sia interpretato come il start discussione altrimenti sarebbe il stop discussione.

È quindi possibile passare l'oggetto porzione alla sequenza:

>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]

È interessante che anche gli intervalli prendano a fette:

>>> range(100)[last_nine_slice]
range(91, 100)

Considerazioni sulla memoria:

Poiché le sezioni di elenchi Python creano nuovi oggetti nella memoria, un'altra importante funzione da tenere presente è itertools.islice. In genere si vorrà eseguire un'iterazione su una porzione, non solo averla creata staticamente in memoria. islice è perfetto per questo. Un avvertimento, non supporta argomenti negativi a start, stop, o step, quindi se questo è un problema potrebbe essere necessario calcolare gli indici o invertire l'iterabile in anticipo.

length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)

e adesso:

>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]

Il fatto che le porzioni di lista facciano una copia è una caratteristica delle liste stesse. Se stai affettando oggetti avanzati come Pandas DataFrame, potrebbe restituire una vista sull'originale e non una copia.


184
2017-07-12 13:19



E un paio di cose che non erano immediatamente ovvie per me quando ho visto per la prima volta la sintassi slicing:

>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]

Un modo semplice per invertire le sequenze!

E se volevi, per qualche motivo, ogni secondo elemento nella sequenza invertita:

>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]

124
2018-02-03 23:15



Ho trovato questo fantastico tavolo a http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.

Index from rear:    -6  -5  -4  -3  -2  -1      a=[0,1,2,3,4,5]    a[1:]==[1,2,3,4,5]
Index from front:    0   1   2   3   4   5      len(a)==6          a[:5]==[0,1,2,3,4]
                   +---+---+---+---+---+---+    a[0]==0            a[:-2]==[0,1,2,3]
                   | a | b | c | d | e | f |    a[5]==5            a[1:2]==[1]
                   +---+---+---+---+---+---+    a[-1]==5           a[1:-1]==[1,2,3,4]
Slice from front:  :   1   2   3   4   5   :    a[-2]==4
Slice from rear:   :  -5  -4  -3  -2  -1   :
                                                b=a[:]
                                                b==[0,1,2,3,4,5] (shallow copy of a)

84
2017-09-06 06:50



In Python 2.7

Affettare in Python

[a:b:c]

len = length of string, tuple or list

c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.

a --  When c is positive or blank, default is 0. When c is negative, default is -1.

b --  When c is positive or blank, default is len. When c is negative, default is -(len+1).

Capire l'assegnazione dell'indice è molto importante.

In forward direction, starts at 0 and ends at len-1

In backward direction, starts at -1 and ends at -len

Quando dici [a: b: c], stai dicendo a seconda del segno di c (in avanti o indietro), inizia da a e termina in b (escluso l'elemento in bth index). Utilizza la regola di indicizzazione sopra e ricorda che troverai solo elementi in questo intervallo:

-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1

Ma questa gamma continua in entrambe le direzioni all'infinito:

...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....

Per esempio:

             0    1    2   3    4   5   6   7   8   9   10   11
             a    s    t   r    i   n   g
    -9  -8  -7   -6   -5  -4   -3  -2  -1

Se la tua scelta di a, b e c consente di sovrapporsi all'intervallo sopra mentre attraversi le regole per a, b, c sopra, otterrai una lista con elementi (toccati durante il percorso) o otterrai una lista vuota.

Un'ultima cosa: se a e b sono uguali, allora ottieni anche una lista vuota:

>>> l1
[2, 3, 4]

>>> l1[:]
[2, 3, 4]

>>> l1[::-1] # a default is -1 , b default is -(len+1)
[4, 3, 2]

>>> l1[:-4:-1] # a default is -1
[4, 3, 2]

>>> l1[:-3:-1] # a default is -1
[4, 3]

>>> l1[::] # c default is +1, so a default is 0, b default is len
[2, 3, 4]

>>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
[4, 3, 2]


>>> l1[-100:-200:-1] # Interesting
[]

>>> l1[-1:-200:-1] # Interesting
[4, 3, 2]


>>> l1[-1:-1:1]
[]


>>> l1[-1:5:1] # Interesting
[4]


>>> l1[1:-7:1]
[]

>>> l1[1:-7:-1] # Interesting
[3, 2]

>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]

84
2017-10-22 05:33



Dopo averlo usato un po 'mi rendo conto che la descrizione più semplice è che è esattamente la stessa cosa degli argomenti in un ciclo for ...

(from:to:step)

qualcuno di loro è facoltativo

(:to:step)
(from::step)
(from:to)

quindi l'indicizzazione negativa ha solo bisogno di aggiungere la lunghezza della stringa agli indici negativi per comprenderla.

Questo funziona comunque per me ...


47
2018-02-19 20:52