Forstå skivenotasjon

Jeg trenger en god forklaring (referanser er et pluss) på Pythons slice-notasjon.

For meg trenger denne notasjonen litt å plukke opp.

Det ser ekstremt kraftig ut, men jeg har ikke helt fått hodet rundt det.

Løsning

Det er egentlig ganske enkelt:

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

Det er også step-verdien, som kan brukes med hvilken som helst av de ovennevnte:

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

Det viktigste å huske er at :stop-verdien representerer den første verdien som ikke er i det valgte utsnittet. Forskjellen mellom stop og start er altså antall elementer som er valgt (hvis step er 1, som er standard).

Den andre funksjonen er at start eller stop kan være et negativt tall, noe som betyr at det teller fra slutten av matrisen i stedet for begynnelsen. Det vil si at man teller fra slutten av arrayet i stedet for begynnelsen:

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

På samme måte kan step være et negativt tall:

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 er snill mot programmereren hvis det er færre elementer enn du ber om. Hvis du for eksempel ber om a[:-2] og a bare inneholder ett element, får du en tom liste i stedet for en feil. Noen ganger foretrekker du feilen, så du må være klar over at dette kan skje.

Relasjon til slice()-objektet ### Relasjon til slice()-objektet

Slicing-operatoren [] blir faktisk brukt i koden ovenfor med et slice()-objekt som bruker :-notasjonen (som bare er gyldig innenfor []), dvs:

a[start:stop:step]

er ekvivalent med:

a[slice(start, stop, step)]

Slice-objekter oppfører seg også litt forskjellig avhengig av antall argumenter, på samme måte som range(), dvs. både slice(stop) og slice(start, stop[, step]) støttes. For å hoppe over å spesifisere et gitt argument kan man bruke None, slik at f.eks. a[start:] er ekvivalent med a[slice(start, None)] eller a[::-1] er ekvivalent med a[slice(None, None, -1)].

Selv om den :-baserte notasjonen er svært nyttig for enkel slicing, forenkler eksplisitt bruk av slice()-objekter den programmatiske genereringen av slicing.

Kommentarer (7)

Python-opplæringen]1 snakker om det (bla litt nedover til du kommer til delen om slicing).

ASCII-kunstdiagrammet er også nyttig for å huske hvordan skiver fungerer:

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

En måte å huske hvordan skiver fungerer på er å tenke på indeksene som pekende mellom tegn, med venstre kant av det første tegnet nummerert 0. Da har høyre kant av det siste tegnet i en streng med n tegn indeks n.

Kommentarer (2)

Oppregning av mulighetene som grammatikken tillater:

>>> 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]]

Selvfølgelig, hvis (high-low)%stride != 0, vil sluttpunktet være litt lavere enn high-1.

Hvis stride er negativ, endres rekkefølgen litt siden vi teller ned:

>>> 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]]

Utvidet slicing (med komma og ellipser) brukes for det meste bare av spesielle datastrukturer (som NumPy); de grunnleggende sekvensene støtter dem ikke.

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