Je pensais comprendre les bases du découpage de liste en python, mais je recevais une erreur inattendue lors de l'utilisation d'un pas négatif sur une tranche, comme suit:
>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:-1]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-1:-1]
[]
(Notez que cela est en cours d'exécution dans Python 3.5)
Pourquoi un [: - 1: -1] ne passe-t-il pas en arrière dans la tranche a [: - 1] de la même manière que dans toute la liste avec un [:: - 1]?
Je me rends compte que vous pouvez aussi utiliser list.reverse (), mais essayez de mieux comprendre la fonctionnalité de slice sous-jacente de python.
Le premier -1
dans a[:-1:-1]
ne signifie pas ce que vous pensez qu'il fait.
Lors du découpage, les indices de début/fin négatifs ne sont pas interprétés littéralement. Au lieu de cela, ils sont utilisés pour se référer facilement à la fin de la liste (c'est-à-dire qu'ils sont relatifs à len(a)
). Cela se produit indépendamment de la direction du découpage.
Cela signifie que
a[:-1:-1]
est équivalent à
a[:len(a)-1:-1]
Lorsqu’il est omis lors du découpage inversé, l’index de départ est défini par défaut sur len(a)-1
, ce qui rend l’équivalent ci-dessus équivalent
a[len(a)-1:len(a)-1:-1]
Cela donne toujours une liste vide, puisque les index de début et de fin sont identiques et que l'index de fin est exclusif.
Pour découper en sens inverse jusqu’à l’élément zeroth inclus, vous pouvez utiliser l’une des notations suivantes:
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:None:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-len(a)-1:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Lorsque vous tapez [1, 2, 3, ...][1:4:1]
, il est identique à [1, 2, 3, ...][slice(1, 4, 1)]
. Donc, 1:4:1
est l’abréviation de l’objet slice
. slice
signature est slice(stop)
ou slice(start, stop[, step])
et vous pouvez également utiliser None
pour les arguments.
:: -> slice(None, None, None)
:4 -> slice(4)
# and so on
Supposons que nous ayons [a: b: c]
. Règles pour les index seront comme suit:
c
est cochée. La valeur par défaut est +1
, le signe c
indique le sens en avant ou en arrière du pas. La valeur absolue de c
indique la taille de l'étape. a
est coché. Lorsque c
est positif ou None
, la valeur par défaut de a
est 0
. Lorsque c
est négatif, la valeur par défaut de a
est -1
.b
est coché. Lorsque c
est positif ou None
, la valeur par défaut de b
est len
. Lorsque c
est négatif, la valeur par défaut de b
est -(len+1)
.Note 1: Les tranches dégénérées en Python sont traitées avec élégance:
len
ou 0
. c
). Note 2: En gros, Python récupère des éléments alors que cette condition (a < b) if (c > 0) else (a > b)
est True
(mise à jour a += c
à chaque étape). De plus, tous les index négatifs sont remplacés par len - index
.
Si vous combinez ces règles et vos notes, vous comprendrez pourquoi vous avez une liste vide. Dans ton cas:
In[1]: [1, 2, 3, 4, 5, 6][:-1:-1] # `c` is negative so `a` is -1 and `b` is -1
Out[1]: []
# it is the same as:
In[2]: [1, 2, 3, 4, 5, 6][-1: -1: -1] # which will produce you an empty list
Out[2]: []
Il existe une très bonne discussion sur la notation de tranche: Expliquez la notation de tranche de Python !
Je trouve généralement utile de découper un objet range
- (cela n’est possible que dans python3 - en python2 range
produit une list
et xrange
ne peut pas être découpé en tranches) si j’ai besoin de savoir quels index sont utilisés pour une liste de longueur donnée:
>>> range(10)[::-1]
range(9, -1, -1)
>>> range(10)[:-1]
range(0, 9)
Et dans votre dernier cas:
>>> range(10)[:-1:-1]
range(9, 9, -1)
Cela explique aussi ce qui s'est passé. Le premier index est 9, mais 9 n'est pas inférieur à l'index d'arrêt 9 (notez qu'en python, l'index d'arrêt est exclu ), de sorte qu'il s'arrête sans donner d'élément.
Notez que l'indexation peut également être appliquée de manière séquentielle:
>>> list(range(10))[::-1][:-1] # first reverse then exclude last item.
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> list(range(10))[:-1][::-1] # other way around
[8, 7, 6, 5, 4, 3, 2, 1, 0]
slice
fonctionne de manière similaire à range
en ce que, lorsque vous définissez l'argument step
en nombre négatif, les arguments start
et stop
fonctionnent dans le sens opposé.
>>> list(range(9, -1, -1)) == a[::-1]
True
Quelques exemples peuvent aider à rendre cela plus clair:
>>> a[6:2:-2]
[6, 4]
>>> a[0:None:1] == a[::]
True
>>> a[-1:None:-1] == a[::-1]
True
>>> a[-2:None:-1] == a[:-1][::-1]
True