Noções básicas sobre notação de fatia

3285

Eu preciso de uma boa explicação (as referências são um plus) na notação de fatia do Python.

Para mim, essa notação precisa de um pouco de atenção.

Parece extremamente poderoso, mas ainda não consegui entender.

Simon
fonte

Respostas:

4508

Na verdade, é bem simples:

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

Há também o stepvalor, que pode ser usado com qualquer um dos itens acima:

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

O ponto principal a lembrar é que o :stopvalor representa o primeiro valor que não está na fatia selecionada. Portanto, a diferença entre stope starté o número de elementos selecionados (se stepfor 1, o padrão).

O outro recurso é esse startou stoppode ser um número negativo , o que significa que conta desde o final da matriz em vez do início. Assim:

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

Da mesma forma, steppode ser um número 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 é gentil com o programador se houver menos itens do que você solicita. Por exemplo, se você solicitar a[:-2]e acontiver apenas um elemento, obterá uma lista vazia em vez de um erro. Às vezes você prefere o erro, portanto, saiba que isso pode acontecer.

Relação a slice() objeto

O operador de fatiamento []está realmente sendo usado no código acima com um slice()objeto usando a :notação (que é válida apenas dentro []), ou seja:

a[start:stop:step]

é equivalente a:

a[slice(start, stop, step)]

Os objetos de fatia também se comportam de maneira ligeiramente diferente, dependendo do número de argumentos, da mesma forma que range(), por exemplo , ambos slice(stop)e slice(start, stop[, step])são suportados. Para pular a especificação de um determinado argumento, pode-se usar None, de modo que, por exemplo, a[start:]seja equivalente a a[slice(start, None)]ou a[::-1]seja a[slice(None, None, -1)].

Embora a :notação baseada em seja muito útil para o fatiamento simples, o uso explícito de slice()objetos simplifica a geração programática do fatiamento.

Greg Hewgill
fonte
122
Fatiar tipos internos retorna uma cópia, mas isso não é universal. Notavelmente, fatiar matrizes NumPy retorna uma exibição que compartilha memória com o original.
Beni Cherniavsky-Paskin
43
Esta é uma bela resposta com os votos para provar isso, mas falta uma coisa: você pode substituir Nonequalquer um dos espaços vazios. Por exemplo, [None:None]faz uma cópia inteira. Isso é útil quando você precisa especificar o final do intervalo usando uma variável e precisa incluir o último item.
Mark Ransom
6
O que realmente me incomoda é que o python diz que quando você não define o início e o fim, o padrão é 0 e o comprimento da sequência. Portanto, em teoria, quando você usa "abcdef" [:: - 1], ele deve ser transformado em "abcdef" [0: 6: -1], mas essas duas expressões não obtêm a mesma saída. Eu sinto que algo está faltando na documentação python desde a criação da linguagem.
axell13
6
E eu sei que "abcdef" [:: - 1] é transformado em "abcdef" [6: -7: -1], por isso, a melhor maneira de explicar seria: deixar len ser o comprimento da seqüência. Se a etapa for positiva , os padrões para início e fim são 0 e len . Caso
contrário
4
Como stackoverflow.com/questions/39241529/… está marcado como um dupe disso, faria sentido adicionar uma seção com o que delfaz a notação de fatia wrt. Em particular, del arr[:]não é imediatamente óbvio ( "arr [:] faz uma cópia, o mesmo acontece del exclusão que copiar ???" etc.)
khazhyk
538

O tutorial do Python fala sobre isso (role um pouco para baixo até chegar à parte sobre fatiar).

O diagrama de arte ASCII também é útil para lembrar como as fatias funcionam:

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

Uma maneira de lembrar como as fatias funcionam é pensar nos índices como apontando entre os caracteres, com a borda esquerda do primeiro caractere numerada 0. Então, a borda direita do último caractere de uma seqüência de n caracteres tem o índice n .

Hans Nowak
fonte
10
Essa sugestão funciona para um passo positivo, mas não para um passo negativo. Do diagrama, espero a[-4,-6,-1]ser, yPmas é ty. O que sempre funciona é pensar em caracteres ou slots e usar a indexação como um intervalo semiaberto - abertura à direita se for positivo, abertura à esquerda se for um passo negativo.
Aguadopd 27/05/19
Mas não há como reduzir para um conjunto vazio a partir do final (como x[:0]acontece quando se inicia do início), então você precisa criar matrizes pequenas para casos especiais. : /
endolith
412

Enumerando as possibilidades permitidas pela gramática:

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

Claro se (high-low)%stride != 0 , então o ponto final será um pouco menor que high-1.

E se stride for negativo, a ordem será alterada um pouco, pois estamos em contagem regressiva:

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

Fatias estendidas (com vírgulas e elipses) são usadas principalmente apenas por estruturas de dados especiais (como NumPy); as seqüências básicas não as suportam.

>>> class slicee:
...     def __getitem__(self, item):
...         return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
efémero
fonte
Na verdade, ainda há algo deixado de fora, por exemplo, se eu digitar 'apple' [4: -4: -1] eu recebo 'elp', python está traduzindo o -4 para 1 talvez?
liyuan 01/01
observe que os backticks foram preteridos em favor derepr
wjandrea
@liyuan O tipo de implementação __getitem__é; seu exemplo é equivalente a apple[slice(4, -4, -1)].
chepner
320

As respostas acima não discutem a atribuição de fatia. Para entender a atribuição de fatia, é útil adicionar outro conceito à arte ASCII:

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

>>> p = ['P','y','t','h','o','n']
# Why the two sets of numbers:
# indexing gives items, not lists
>>> p[0]
 'P'
>>> p[5]
 'n'

# Slicing gives lists
>>> p[0:1]
 ['P']
>>> p[0:2]
 ['P','y']

Uma heurística é, para uma fatia de zero a n, pense: "zero é o começo, comece do começo e coloque n itens em uma lista".

>>> p[5] # the last of six items, indexed from zero
 'n'
>>> p[0:5] # does NOT include the last item!
 ['P','y','t','h','o']
>>> p[0:6] # not p[0:5]!!!
 ['P','y','t','h','o','n']

Outra heurística é: "para qualquer fatia, substitua o início por zero, aplique a heurística anterior para chegar ao final da lista e conte o primeiro número de volta para cortar os itens do início"

>>> p[0:4] # Start at the beginning and count out 4 items
 ['P','y','t','h']
>>> p[1:4] # Take one item off the front
 ['y','t','h']
>>> p[2:4] # Take two items off the front
 ['t','h']
# etc.

A primeira regra da atribuição de fatia é que, como a fatia retorna uma lista, a atribuição de fatia exige uma lista (ou outra iterável):

>>> p[2:3]
 ['t']
>>> p[2:3] = ['T']
>>> p
 ['P','y','T','h','o','n']
>>> p[2:3] = 't'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable

A segunda regra de atribuição de fatia, que você também pode ver acima, é que qualquer parte da lista é retornada pela indexação de fatia, é a mesma parte que é alterada pela atribuição de fatia:

>>> p[2:4]
 ['T','h']
>>> p[2:4] = ['t','r']
>>> p
 ['P','y','t','r','o','n']

A terceira regra de atribuição de fatia é que a lista atribuída (iterável) não precisa ter o mesmo comprimento; a fatia indexada é simplesmente cortada e substituída em massa pelo que estiver sendo atribuído:

>>> p = ['P','y','t','h','o','n'] # Start over
>>> p[2:4] = ['s','p','a','m']
>>> p
 ['P','y','s','p','a','m','o','n']

A parte mais difícil de se acostumar é a atribuição de fatias vazias. Usando as heurísticas 1 e 2, é fácil indexar uma fatia vazia:

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []

E depois que você vê isso, a atribuição de fatia à fatia vazia também faz sentido:

>>> p = ['P','y','t','h','o','n']
>>> p[2:4] = ['x','y'] # Assigned list is same length as slice
>>> p
 ['P','y','x','y','o','n'] # Result is same length
>>> p = ['P','y','t','h','o','n']
>>> p[3:4] = ['x','y'] # Assigned list is longer than slice
>>> p
 ['P','y','t','x','y','o','n'] # The result is longer
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
 ['P','y','t','h','x','y','o','n'] # The result is longer still

Observe que, como não estamos alterando o segundo número da fatia (4), os itens inseridos sempre se comparam com o 'o', mesmo quando estamos atribuindo a fatia vazia. Portanto, a posição para a atribuição de fatia vazia é a extensão lógica das posições para as atribuições de fatia não vazias.

Fazendo um backup, o que acontece quando você continua com nossa procissão de contagem do início da fatia?

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []

Com a fatia, uma vez que você termina, você termina; não começa a cortar para trás. No Python, você não obtém avanços negativos, a menos que você os solicite explicitamente usando um número negativo.

>>> p[5:3:-1]
 ['n','o']

Existem algumas consequências estranhas na regra "quando terminar, pronto":

>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []
>>> p[6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

De fato, comparado à indexação, o fatiamento do Python é bizarramente à prova de erros:

>>> p[100:200]
 []
>>> p[int(2e99):int(1e99)]
 []

Às vezes, isso pode ser útil, mas também pode levar a um comportamento estranho:

>>> p
 ['P', 'y', 't', 'h', 'o', 'n']
>>> p[int(2e99):int(1e99)] = ['p','o','w','e','r']
>>> p
 ['P', 'y', 't', 'h', 'o', 'n', 'p', 'o', 'w', 'e', 'r']

Dependendo da sua aplicação, isso pode ... ou não ... ser o que você estava esperando lá!


Abaixo está o texto da minha resposta original. Tem sido útil para muitas pessoas, então eu não queria excluí-lo.

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

Isso também pode esclarecer a diferença entre fatiar e indexar.

David M. Perlman
fonte
246

Explicar a notação de fatia do Python

Em suma, os pontos ( :) em notação subscrita ( subscriptable[subscriptarg]) Faz notação slice - que tem os argumentos opcionais, start, stop, step:

sliceable[start:stop:step]

A fatia de Python é uma maneira computacionalmente rápida de acessar metodicamente partes de seus dados. Na minha opinião, para ser um programador intermediário de Python, é um aspecto da linguagem com a qual é necessário estar familiarizado.

Definições importantes

Para começar, vamos definir alguns termos:

start: o índice inicial da fatia, incluirá o elemento nesse índice, a menos que seja o mesmo que stop , o padrão é 0, ou seja, o primeiro índice. Se for negativo, significa iniciar nitens a partir do final.

stop: o índice final da fatia, ele não inclui o elemento nesse índice, o padrão é o comprimento da sequência cortada, ou seja, até e incluindo o final.

passo: a quantidade pela qual o índice aumenta, o padrão é 1. Se for negativo, você estará fatiando o iterável ao contrário.

Como funciona a indexação

Você pode criar qualquer um desses números positivos ou negativos. O significado dos números positivos é simples, mas para números negativos, assim como índices em Python, você contar para trás a partir do final para o início e parada , e para a etapa , você simplesmente diminuir o seu índice. Este exemplo é do tutorial da documentação , mas eu o modifiquei um pouco para indicar qual item de uma sequência cada índice faz referência:

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

Como funciona o fatiamento

Para usar a notação de fatia com uma sequência que a suporta, você deve incluir pelo menos um dois pontos entre colchetes que seguem a sequência (que realmente implementa o __getitem__método da sequência, de acordo com o modelo de dados Python ).

A notação de fatia funciona assim:

sequence[start:stop:step]

E lembre-se de que existem padrões para iniciar , parar e etapa , para acessar os padrões, simplesmente deixe de fora o argumento.

A notação de fatia para obter os últimos nove elementos de uma lista (ou qualquer outra sequência que a suporte, como uma string) ficaria assim:

my_list[-9:]

Quando vejo isso, li a parte entre parênteses como "9ª do fim até o fim". (Na verdade, eu abrevio isso mentalmente como "-9, em")

Explicação:

A notação completa é

my_list[-9:None:None]

e para substituir os padrões (na verdade, quando stepé negativo, stopo padrão é -len(my_list) - 1, portanto, Nonepara parar realmente significa que ele vai para a etapa final que leva):

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

O cólon , :, é o que diz ao Python que você está dando-lhe uma fatia e não um índice regular. É por isso que a maneira idiomática de fazer uma cópia superficial das listas no Python 2 é

list_copy = sequence[:]

E limpá-los é com:

del my_list[:]

(Python 3 obtém um método list.copye list.clear.)

Quando stepnegativo, os padrões starte as stopalterações são

Por padrão, quando o stepargumento está vazio (ou None), é atribuído a +1.

Mas você pode passar um número inteiro negativo e a lista (ou a maioria das outras slicables padrão) será cortada do fim ao começo.

Assim, uma fatia negativa alterará os padrões para startestop !

Confirmando isso na fonte

Eu gosto de incentivar os usuários a lerem a fonte e a documentação. O código fonte dos objetos de fatia e essa lógica são encontrados aqui . Primeiro, determinamos se stepé negativo:

 step_is_negative = step_sign < 0;

Nesse caso, o limite inferior -1 significa que cortamos todo o caminho até o início, inclusive, e o limite superior é o comprimento menos 1, o que significa que começamos no final. (Observe que a semântica disso -1é diferente da -1que os usuários podem passar índices no Python, indicando o último item.)

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

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

Caso contrário, stepé positivo, e o limite inferior será zero e o limite superior (que subimos, mas não incluindo) o comprimento da lista fatiada.

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

Então, talvez seja necessário aplicar os padrões para starte stop- o padrão então para starté calculado como o limite superior quando stepfor negativo:

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

e stop, o limite inferior:

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

Dê um nome descritivo às suas fatias!

Você pode achar útil separar a formação da fatia da passagem para o list.__getitem__método ( é isso que os colchetes fazem ). Mesmo se você não é novo nele, ele mantém seu código mais legível, para que outras pessoas que precisam ler seu código possam entender mais facilmente o que está fazendo.

No entanto, você não pode simplesmente atribuir alguns números inteiros separados por dois pontos a uma variável. Você precisa usar o objeto de fatia:

last_nine_slice = slice(-9, None)

O segundo argumento,, Noneé necessário, para que o primeiro argumento seja interpretado como o startargumento, caso contrário, seria o stopargumento .

Você pode passar o objeto de fatia para sua sequência:

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

É interessante que os intervalos também tomem fatias:

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

Considerações sobre memória:

Como fatias de listas Python criam novos objetos na memória, outra função importante a ser observada é itertools.islice. Normalmente, você deseja iterar sobre uma fatia, e não apenas criar estaticamente na memória. isliceé perfeito para isso. Uma ressalva, ele não suporta argumentos negativos para start, stopou step, portanto, se esse é um problema, pode ser necessário calcular índices ou reverter o iterável antecipadamente.

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

e agora:

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

O fato de as fatias da lista fazerem uma cópia é um recurso das próprias listas. Se você estiver cortando objetos avançados como um DataFrame do Pandas, ele poderá retornar uma exibição no original, e não uma cópia.

Aaron Hall
fonte
147

E algumas coisas que não eram imediatamente óbvias para mim quando vi a sintaxe da fatia:

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

Maneira fácil de reverter seqüências!

E se você quisesse, por algum motivo, cada segundo item na sequência reversa:

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

No Python 2.7

Corte em 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).

Compreender a atribuição de índice é muito importante.

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

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

Quando você diz [a: b: c], está dizendo que, dependendo do sinal de c (para frente ou para trás), comece em a e termine em b (excluindo o elemento no b-ésimo índice). Use a regra de indexação acima e lembre-se de que você encontrará apenas elementos neste intervalo:

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

Mas esse intervalo continua nas duas direções infinitamente:

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

Por exemplo:

             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 sua escolha de a, bec permitir sobreposição com o intervalo acima, conforme você percorre as regras de a, b, c acima, você obterá uma lista com elementos (tocados durante a travessia) ou obterá uma lista vazia.

Uma última coisa: se aeb são iguais, você também recebe uma lista vazia:

>>> 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]
Ankur Agarwal
fonte
2
outro exemplo interessante: o a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]que resulta em[9]
Deviacium
96

Encontrei esta excelente tabela em 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)
AdrianoFerrari
fonte
65

Depois de usá-lo um pouco, percebo que a descrição mais simples é que é exatamente o mesmo que os argumentos em um forloop ...

(from:to:step)

Qualquer um deles é opcional:

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

Em seguida, a indexação negativa precisa apenas que você adicione o comprimento da sequência aos índices negativos para entendê-la.

Isso funciona para mim de qualquer maneira ...

Simon
fonte
52

Acho mais fácil lembrar como funciona e, em seguida, posso descobrir qualquer combinação específica de início / parada / etapa.

É instrutivo entender range()primeiro:

def range(start=0, stop, step=1):  # Illegal syntax, but that's the effect
    i = start
    while (i < stop if step > 0 else i > stop):
        yield i
        i += step

Comece de start, incremente por step, não alcance stop. Muito simples.

O que deve ser lembrado sobre o passo negativo é que esse stopé sempre o fim excluído, seja ele maior ou menor. Se você deseja a mesma fatia na ordem oposta, é muito mais fácil fazer a reversão separadamente: por exemplo, 'abcde'[1:-2][::-1]corta um caractere da esquerda, dois da direita e depois inverte. (Veja também reversed().)

O fatiamento da sequência é o mesmo, exceto que ele normaliza primeiro os índices negativos e nunca pode sair da sequência:

TODO : O código abaixo tinha um erro com "nunca sair da sequência" quando abs (etapa)> 1; Eu acho que o corrigi para estar correto, mas é difícil de entender.

def this_is_how_slicing_works(seq, start=None, stop=None, step=1):
    if start is None:
        start = (0 if step > 0 else len(seq)-1)
    elif start < 0:
        start += len(seq)
    if not 0 <= start < len(seq):  # clip if still outside bounds
        start = (0 if step > 0 else len(seq)-1)
    if stop is None:
        stop = (len(seq) if step > 0 else -1)  # really -1, not last element
    elif stop < 0:
        stop += len(seq)
    for i in range(start, stop, step):
        if 0 <= i < len(seq):
            yield seq[i]

Não se preocupe com os is Nonedetalhes - lembre-se de que a omissão starte / ou stopsempre faz a coisa certa para fornecer toda a sequência.

A normalização de índices negativos primeiro permite que o início e / ou a parada sejam contados a partir do final independentemente: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'apesar range(1,-2) == []. Às vezes, a normalização é considerada "módulo do comprimento", mas observe que ele adiciona o comprimento apenas uma vez: por exemplo, 'abcde'[-53:42]é apenas a string inteira.

Beni Cherniavsky-Paskin
fonte
3
Não this_is_how_slicing_worksé o mesmo que fatia python. O EG [0, 1, 2][-5:3:3]obterá [0] em python, mas list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))obterá [1].
Eastsun
@Eastsun Opa, você está certo! Um caso mais claro: range(4)[-200:200:3] == [0, 3]mas list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]. Meu if 0 <= i < len(seq):foi uma tentativa de implementar "nunca saia da sequência" simplesmente, mas está errado na etapa> 1. Vou reescrevê-lo hoje mais tarde (com testes).
Beni Cherniavsky-Paskin
40

Eu mesmo uso o método "um índice aponta entre elementos" para pensar sobre isso, mas uma maneira de descrevê-lo que às vezes ajuda os outros a entender é:

mylist[X:Y]

X é o índice do primeiro elemento que você deseja.
Y é o índice do primeiro elemento que você não deseja.

Steve Losh
fonte
40
Index:
      ------------>
  0   1   2   3   4
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
  0  -4  -3  -2  -1
      <------------

Slice:
    <---------------|
|--------------->
:   1   2   3   4   :
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
:  -4  -3  -2  -1   :
|--------------->
    <---------------|

Espero que isso ajude você a modelar a lista em Python.

Referência: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

xiaoyu
fonte
38

Notação de fatia do Python:

a[start:end:step]
  • Para starte end, valores negativos são interpretados como sendo relativos ao final da sequência.
  • Índices positivos para endindicam a posição após o último elemento a ser incluído.
  • Os valores do branco são padronizados como se segue: [+0:-0:1].
  • O uso de uma etapa negativa inverte a interpretação starteend

A notação se estende a matrizes (numpy) e matrizes multidimensionais. Por exemplo, para dividir colunas inteiras, você pode usar:

m[::,0:2:] ## slice the first two columns

As fatias contêm referências, não cópias, dos elementos da matriz. Se você deseja fazer uma cópia separada em uma matriz, pode usar deepcopy().

nobar
fonte
34

Você também pode usar a atribuição de fatia para remover um ou mais elementos de uma lista:

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

Isto é apenas para informações adicionais ... Considere a lista abaixo

>>> l=[12,23,345,456,67,7,945,467]

Alguns outros truques para reverter a lista:

>>> l[len(l):-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[len(l)::-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[::-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[-1:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
Arindam Roychowdhury
fonte
33

É assim que ensino fatias para iniciantes:

Entendendo a diferença entre indexação e fatia:

O Wiki Python tem essa imagem incrível que distingue claramente a indexação e o fatiamento.

Digite a descrição da imagem aqui

É uma lista com seis elementos. Para entender melhor o fatiamento, considere essa lista como um conjunto de seis caixas juntas. Cada caixa tem um alfabeto.

A indexação é como lidar com o conteúdo da caixa. Você pode verificar o conteúdo de qualquer caixa. Mas você não pode verificar o conteúdo de várias caixas ao mesmo tempo. Você pode até substituir o conteúdo da caixa. Mas você não pode colocar duas bolas em uma caixa ou substituir duas por vez.

In [122]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [123]: alpha
Out[123]: ['a', 'b', 'c', 'd', 'e', 'f']

In [124]: alpha[0]
Out[124]: 'a'

In [127]: alpha[0] = 'A'

In [128]: alpha
Out[128]: ['A', 'b', 'c', 'd', 'e', 'f']

In [129]: alpha[0,1]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-129-c7eb16585371> in <module>()
----> 1 alpha[0,1]

TypeError: list indices must be integers, not tuple

Cortar é como lidar com as próprias caixas. Você pode pegar a primeira caixa e colocá-la em outra mesa. Para pegar a caixa, tudo o que você precisa saber é a posição de início e fim da caixa.

Você pode até pegar as três primeiras caixas ou as duas últimas caixas ou todas as caixas entre 1 e 4. Portanto, você pode escolher qualquer conjunto de caixas se souber o início e o final. Essas posições são chamadas de posições inicial e final.

O interessante é que você pode substituir várias caixas ao mesmo tempo. Além disso, você pode colocar várias caixas onde quiser.

In [130]: alpha[0:1]
Out[130]: ['A']

In [131]: alpha[0:1] = 'a'

In [132]: alpha
Out[132]: ['a', 'b', 'c', 'd', 'e', 'f']

In [133]: alpha[0:2] = ['A', 'B']

In [134]: alpha
Out[134]: ['A', 'B', 'c', 'd', 'e', 'f']

In [135]: alpha[2:2] = ['x', 'xx']

In [136]: alpha
Out[136]: ['A', 'B', 'x', 'xx', 'c', 'd', 'e', 'f']

Corte com etapa:

Até agora você selecionou caixas continuamente. Mas, às vezes, você precisa atender discretamente. Por exemplo, você pode escolher cada segunda caixa. Você pode até pegar todas as caixas do final. Este valor é chamado tamanho da etapa. Isso representa a lacuna entre seus captadores sucessivos. O tamanho da etapa deve ser positivo se você estiver escolhendo caixas do começo ao fim e vice-versa.

In [137]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [142]: alpha[1:5:2]
Out[142]: ['b', 'd']

In [143]: alpha[-1:-5:-2]
Out[143]: ['f', 'd']

In [144]: alpha[1:5:-2]
Out[144]: []

In [145]: alpha[-1:-5:2]
Out[145]: []

Como o Python descobre os parâmetros ausentes:

Ao fatiar, se você deixar de fora algum parâmetro, o Python tenta descobrir isso automaticamente.

Se você verificar o código fonte do CPython , encontrará uma função chamada PySlice_GetIndicesEx () que calcula os índices de uma fatia para qualquer parâmetro. Aqui está o código equivalente lógico no Python.

Essa função utiliza um objeto Python e parâmetros opcionais para fatiar e retorna o comprimento de início, parada, etapa e fatia da fatia solicitada.

def py_slice_get_indices_ex(obj, start=None, stop=None, step=None):

    length = len(obj)

    if step is None:
        step = 1
    if step == 0:
        raise Exception("Step cannot be zero.")

    if start is None:
        start = 0 if step > 0 else length - 1
    else:
        if start < 0:
            start += length
        if start < 0:
            start = 0 if step > 0 else -1
        if start >= length:
            start = length if step > 0 else length - 1

    if stop is None:
        stop = length if step > 0 else -1
    else:
        if stop < 0:
            stop += length
        if stop < 0:
            stop = 0 if step > 0 else -1
        if stop >= length:
            stop = length if step > 0 else length - 1

    if (step < 0 and stop >= start) or (step > 0 and start >= stop):
        slice_length = 0
    elif step < 0:
        slice_length = (stop - start + 1)/(step) + 1
    else:
        slice_length = (stop - start - 1)/(step) + 1

    return (start, stop, step, slice_length)

Essa é a inteligência que está presente atrás das fatias. Como o Python possui uma função interna chamada slice, você pode passar alguns parâmetros e verificar com que inteligência ele calcula os parâmetros ausentes.

In [21]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [22]: s = slice(None, None, None)

In [23]: s
Out[23]: slice(None, None, None)

In [24]: s.indices(len(alpha))
Out[24]: (0, 6, 1)

In [25]: range(*s.indices(len(alpha)))
Out[25]: [0, 1, 2, 3, 4, 5]

In [26]: s = slice(None, None, -1)

In [27]: range(*s.indices(len(alpha)))
Out[27]: [5, 4, 3, 2, 1, 0]

In [28]: s = slice(None, 3, -1)

In [29]: range(*s.indices(len(alpha)))
Out[29]: [5, 4]

Nota: Esta postagem foi originalmente escrita no meu blog The Intelligence Behind Python Slices .

ChillarAnand
fonte
29

Como regra geral, escrever código com muitos valores de índice codificados leva a uma bagunça de legibilidade e manutenção. Por exemplo, se você voltar ao código um ano depois, você o examinará e se perguntará o que estava pensando quando o escreveu. A solução mostrada é simplesmente uma maneira de indicar mais claramente o que seu código está realmente fazendo. Em geral, a fatia interna () cria um objeto de fatia que pode ser usado em qualquer lugar em que uma fatia seja permitida. Por exemplo:

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]

Se você tiver uma instância de fatia s, poderá obter mais informações sobre ela olhando para os atributos s.start, s.stop e s.step, respectivamente. Por exemplo:

>>> a = slice(10, 50, 2)
>>> a.start
10
>>> a.stop
50
>>> a.step
2
>>>
Python_Dude
fonte
25

1. Notação de fatia

Para simplificar, lembre-se de que a fatia possui apenas uma forma:

s[start:end:step]

e aqui está como isso funciona:

  • s: um objeto que pode ser cortado
  • start: primeiro índice para iniciar a iteração
  • end: último índice, NOTE que esse endíndice não será incluído na fatia resultante
  • step: escolher elemento a cada stepíndice

Outra coisa importação: tudo start, end, steppode ser omitido! E se eles forem omitidas, seu valor padrão será utilizado: 0, len(s), 1em conformidade.

As variações possíveis são:

# Mostly used variations
s[start:end]
s[start:]
s[:end]

# Step-related variations
s[:end:step]
s[start::step]
s[::step]

# Make a copy
s[:]

NOTA: Se start >= end(considerando apenas quando step>0), o Python retornará uma fatia vazia [].

2. Armadilhas

A parte acima explica os principais recursos sobre como a fatia funciona e funcionará na maioria das ocasiões. No entanto, pode haver armadilhas que você deve prestar atenção, e esta parte as explica.

Índices negativos

A primeira coisa que confunde os alunos de Python é que um índice pode ser negativo! Não entre em pânico: um índice negativo significa contar para trás.

Por exemplo:

s[-5:]    # Start at the 5th index from the end of array,
          # thus returning the last 5 elements.
s[:-5]    # Start at index 0, and end until the 5th index from end of array,
          # thus returning s[0:len(s)-5].

Etapa negativa

Tornar as coisas mais confusas é que também steppode ser negativo!

Um passo negativo significa iterar a matriz para trás: do final ao início, com o índice final incluído e o índice inicial excluído do resultado.

NOTA : quando a etapa é negativa, o valor padrão para starté len(s)(while endnão é igual a 0, porque s[::-1]contém s[0]). Por exemplo:

s[::-1]            # Reversed slice
s[len(s)::-1]      # The same as above, reversed slice
s[0:len(s):-1]     # Empty list

Erro fora do intervalo?

Surpreenda-se: a fatia não gera um IndexError quando o índice está fora da faixa!

Se o índice estiver fora do intervalo, o Python fará o possível para definir o índice para 0ou de len(s)acordo com a situação. Por exemplo:

s[:len(s)+5]      # The same as s[:len(s)]
s[-len(s)-5::]    # The same as s[0:]
s[len(s)+5::-1]   # The same as s[len(s)::-1], and the same as s[::-1]

3. Exemplos

Vamos terminar esta resposta com exemplos, explicando tudo o que discutimos:

# Create our array for demonstration
In [1]: s = [i for i in range(10)]

In [2]: s
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [3]: s[2:]   # From index 2 to last index
Out[3]: [2, 3, 4, 5, 6, 7, 8, 9]

In [4]: s[:8]   # From index 0 up to index 8
Out[4]: [0, 1, 2, 3, 4, 5, 6, 7]

In [5]: s[4:7]  # From index 4 (included) up to index 7(excluded)
Out[5]: [4, 5, 6]

In [6]: s[:-2]  # Up to second last index (negative index)
Out[6]: [0, 1, 2, 3, 4, 5, 6, 7]

In [7]: s[-2:]  # From second last index (negative index)
Out[7]: [8, 9]

In [8]: s[::-1] # From last to first in reverse order (negative step)
Out[8]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

In [9]: s[::-2] # All odd numbers in reversed order
Out[9]: [9, 7, 5, 3, 1]

In [11]: s[-2::-2] # All even numbers in reversed order
Out[11]: [8, 6, 4, 2, 0]

In [12]: s[3:15]   # End is out of range, and Python will set it to len(s).
Out[12]: [3, 4, 5, 6, 7, 8, 9]

In [14]: s[5:1]    # Start > end; return empty list
Out[14]: []

In [15]: s[11]     # Access index 11 (greater than len(s)) will raise an IndexError
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]

IndexError: list index out of range
cizixs
fonte
24

As respostas anteriores não discutem o faturamento multidimensional de matrizes, o que é possível usando o famoso pacote NumPy :

O fatiamento também pode ser aplicado a matrizes multidimensionais.

# Here, a is a NumPy array

>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
>>> a[:2, 0:3:2]
array([[1, 3],
       [5, 7]])

O " :2" antes da vírgula opera na primeira dimensão e o " 0:3:2" depois da vírgula opera na segunda dimensão.

Statham
fonte
4
Apenas um lembrete amigável que você não pode fazer isso em Python list, mas apenas em arrayem Numpy
Mars Lee
15
#!/usr/bin/env python

def slicegraphical(s, lista):

    if len(s) > 9:
        print """Enter a string of maximum 9 characters,
    so the printig would looki nice"""
        return 0;
    # print " ",
    print '  '+'+---' * len(s) +'+'
    print ' ',
    for letter in s:
        print '| {}'.format(letter),
    print '|'
    print " ",; print '+---' * len(s) +'+'

    print " ",
    for letter in range(len(s) +1):
        print '{}  '.format(letter),
    print ""
    for letter in range(-1*(len(s)), 0):
        print ' {}'.format(letter),
    print ''
    print ''


    for triada in lista:
        if len(triada) == 3:
            if triada[0]==None and triada[1] == None and triada[2] == None:
                # 000
                print s+'[   :   :   ]' +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] == None and triada[1] == None and triada[2] != None:
                # 001
                print s+'[   :   :{0:2d} ]'.format(triada[2], '','') +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] == None and triada[1] != None and triada[2] == None:
                # 010
                print s+'[   :{0:2d} :   ]'.format(triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] == None and triada[1] != None and triada[2] != None:
                # 011
                print s+'[   :{0:2d} :{1:2d} ]'.format(triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] == None and triada[2] == None:
                # 100
                print s+'[{0:2d} :   :   ]'.format(triada[0]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] == None and triada[2] != None:
                # 101
                print s+'[{0:2d} :   :{1:2d} ]'.format(triada[0], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] != None and triada[2] == None:
                # 110
                print s+'[{0:2d} :{1:2d} :   ]'.format(triada[0], triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] != None and triada[2] != None:
                # 111
                print s+'[{0:2d} :{1:2d} :{2:2d} ]'.format(triada[0], triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]

        elif len(triada) == 2:
            if triada[0] == None and triada[1] == None:
                # 00
                print s+'[   :   ]    ' + ' = ', s[triada[0]:triada[1]]
            elif triada[0] == None and triada[1] != None:
                # 01
                print s+'[   :{0:2d} ]    '.format(triada[1]) + ' = ', s[triada[0]:triada[1]]
            elif triada[0] != None and triada[1] == None:
                # 10
                print s+'[{0:2d} :   ]    '.format(triada[0]) + ' = ', s[triada[0]:triada[1]]
            elif triada[0] != None and triada[1] != None:
                # 11
                print s+'[{0:2d} :{1:2d} ]    '.format(triada[0],triada[1]) + ' = ', s[triada[0]:triada[1]]

        elif len(triada) == 1:
            print s+'[{0:2d} ]        '.format(triada[0]) + ' = ', s[triada[0]]


if __name__ == '__main__':
    # Change "s" to what ever string you like, make it 9 characters for
    # better representation.
    s = 'COMPUTERS'

    # add to this list different lists to experement with indexes
    # to represent ex. s[::], use s[None, None,None], otherwise you get an error
    # for s[2:] use s[2:None]

    lista = [[4,7],[2,5,2],[-5,1,-1],[4],[-4,-6,-1], [2,-3,1],[2,-3,-1], [None,None,-1],[-5,None],[-5,0,-1],[-5,None,-1],[-1,1,-2]]

    slicegraphical(s, lista)

Você pode executar esse script e experimentá-lo. Abaixo estão alguns exemplos que eu obtive do script.

  +---+---+---+---+---+---+---+---+---+
  | C | O | M | P | U | T | E | R | S |
  +---+---+---+---+---+---+---+---+---+
  0   1   2   3   4   5   6   7   8   9   
 -9  -8  -7  -6  -5  -4  -3  -2  -1 

COMPUTERS[ 4 : 7 ]     =  UTE
COMPUTERS[ 2 : 5 : 2 ] =  MU
COMPUTERS[-5 : 1 :-1 ] =  UPM
COMPUTERS[ 4 ]         =  U
COMPUTERS[-4 :-6 :-1 ] =  TU
COMPUTERS[ 2 :-3 : 1 ] =  MPUT
COMPUTERS[ 2 :-3 :-1 ] =  
COMPUTERS[   :   :-1 ] =  SRETUPMOC
COMPUTERS[-5 :   ]     =  UTERS
COMPUTERS[-5 : 0 :-1 ] =  UPMO
COMPUTERS[-5 :   :-1 ] =  UPMOC
COMPUTERS[-1 : 1 :-2 ] =  SEUM
[Finished in 0.9s]

Ao usar uma etapa negativa, observe que a resposta é deslocada para a direita por 1.

mahmoh
fonte
14

Meu cérebro parece feliz em aceitar que lst[start:end]contém o startquinto item. Eu poderia até dizer que é uma "suposição natural".

Mas, ocasionalmente, surge uma dúvida e meu cérebro pede garantias de que não contém o end-ésimo elemento.

Nestes momentos, confio neste teorema simples:

for any n,    lst = lst[:n] + lst[n:]

Esta propriedade muito me diz que lst[start:end]não contém o enditem de -ésimo porque ele está em lst[end:].

Observe que esse teorema é verdadeiro para qualquer num. Por exemplo, você pode verificar se

lst = range(10)
lst[:-42] + lst[-42:] == lst

retorna True.

Robert
fonte
12

Na minha opinião, você entenderá e memorizará melhor a notação de fatiamento de strings do Python se a observar da seguinte maneira (continue lendo).

Vamos trabalhar com a seguinte string ...

azString = "abcdefghijklmnopqrstuvwxyz"

Para quem não sabe, você pode criar qualquer substring azStringusando a notaçãoazString[x:y]

Vindo de outras linguagens de programação, é aí que o senso comum fica comprometido. O que são x e y?

Tive que me sentar e executar vários cenários em minha busca por uma técnica de memorização que me ajudasse a lembrar o que xey eram e me ajudasse a cortar as cordas corretamente na primeira tentativa.

Minha conclusão é que xey devem ser vistos como os índices de contorno que cercam as strings que queremos extrair. Portanto, devemos ver a expressão como azString[index1, index2]ou ainda mais clara como azString[index_of_first_character, index_after_the_last_character].

Aqui está um exemplo de visualização disso ...

Letters   a b c d e f g h i j ...
         ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
             ┊           ┊
Indexes  0 1 2 3 4 5 6 7 8 9 ...
             ┊           ┊
cdefgh    index1       index2

Portanto, tudo o que você precisa fazer é definir index1 e index2 com os valores que cercam a substring desejada. Por exemplo, para obter a subcadeia "cdefgh", você pode usarazString[2:8] , porque o índice no lado esquerdo de "c" é 2 e o índice no tamanho certo de "h" é 8.

Lembre-se de que estamos estabelecendo limites. E esses limites são as posições em que você pode colocar alguns colchetes que serão enrolados ao redor da substring assim ...

ab [ cdefgh ] ij

Esse truque funciona o tempo todo e é fácil de memorizar.

asiby
fonte
11

A maioria das respostas anteriores esclarece perguntas sobre a notação de fatia.

A sintaxe de indexação estendida usada para fatiar é aList[start:stop:step]e exemplos básicos são:

Digite a descrição da imagem aqui:

Mais exemplos de fatias : 15 fatias estendidas

Roshan Bagdiya
fonte
10

No Python, a forma mais básica de fatiar é a seguinte:

l[start:end]

onde lestá uma coleção, starté um índice inclusivo e endé um índice exclusivo.

In [1]: l = list(range(10))

In [2]: l[:5] # First five elements
Out[2]: [0, 1, 2, 3, 4]

In [3]: l[-5:] # Last five elements
Out[3]: [5, 6, 7, 8, 9]

Ao fatiar desde o início, você pode omitir o índice zero e, ao fatiar até o final, pode omitir o índice final, pois é redundante, portanto, não seja detalhado:

In [5]: l[:3] == l[0:3]
Out[5]: True

In [6]: l[7:] == l[7:len(l)]
Out[6]: True

Inteiros negativos são úteis ao fazer compensações em relação ao final de uma coleção:

In [7]: l[:-1] # Include all elements but the last one
Out[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8]

In [8]: l[-3:] # Take the last three elements
Out[8]: [7, 8, 9]

É possível fornecer índices que estão fora dos limites ao fatiar, como:

In [9]: l[:20] # 20 is out of index bounds, and l[20] will raise an IndexError exception
Out[9]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [11]: l[-20:] # -20 is out of index bounds, and l[-20] will raise an IndexError exception
Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Lembre-se de que o resultado do fatiamento de uma coleção é uma coleção totalmente nova. Além disso, ao usar a notação de fatia em atribuições, o comprimento das atribuições de fatia não precisa ser o mesmo. Os valores antes e depois da fatia atribuída serão mantidos e a coleção será reduzida ou aumentada para conter os novos valores:

In [16]: l[2:6] = list('abc') # Assigning fewer elements than the ones contained in the sliced collection l[2:6]

In [17]: l
Out[17]: [0, 1, 'a', 'b', 'c', 6, 7, 8, 9]

In [18]: l[2:5] = list('hello') # Assigning more elements than the ones contained in the sliced collection l [2:5]

In [19]: l
Out[19]: [0, 1, 'h', 'e', 'l', 'l', 'o', 6, 7, 8, 9]

Se você omitir o índice inicial e final, você fará uma cópia da coleção:

In [14]: l_copy = l[:]

In [15]: l == l_copy and l is not l_copy
Out[15]: True

Se os índices inicial e final forem omitidos ao executar uma operação de atribuição, todo o conteúdo da coleção será substituído por uma cópia do que é referenciado:

In [20]: l[:] = list('hello...')

In [21]: l
Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']

Além do fatiamento básico, também é possível aplicar a seguinte notação:

l[start:end:step]

where lé uma coleção, starté um índice inclusivo, endé um índice exclusivo e stepé um passo que pode ser usado para incluir cada enésimo item l.

In [22]: l = list(range(10))

In [23]: l[::2] # Take the elements which indexes are even
Out[23]: [0, 2, 4, 6, 8]

In [24]: l[1::2] # Take the elements which indexes are odd
Out[24]: [1, 3, 5, 7, 9]

Usar stepfornece um truque útil para reverter uma coleção em Python:

In [25]: l[::-1]
Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Também é possível usar números inteiros negativos para stepo seguinte exemplo:

In[28]:  l[::-2]
Out[28]: [9, 7, 5, 3, 1]

No entanto, usar um valor negativo para steppode se tornar muito confuso. Além disso, a fim de ser Pythonic , você deve evitar usar start, ende stepem uma única fatia. Caso isso seja necessário, considere fazer isso em duas tarefas (uma para cortar e outra para caminhar).

In [29]: l = l[::2] # This step is for striding

In [30]: l
Out[30]: [0, 2, 4, 6, 8]

In [31]: l = l[1:-1] # This step is for slicing

In [32]: l
Out[32]: [2, 4, 6]
lmiguelvargasf
fonte
10

Quero adicionar um Olá, mundo! exemplo que explica o básico de fatias para os iniciantes. Isto me ajudou bastante.

Vamos ter uma lista com seis valores ['P', 'Y', 'T', 'H', 'O', 'N']:

+---+---+---+---+---+---+
| P | Y | T | H | O | N |
+---+---+---+---+---+---+
  0   1   2   3   4   5

Agora, as fatias mais simples dessa lista são suas sublistas. A notação é [<index>:<index>]e a chave é lê-la assim:

[ start cutting before this index : end cutting before this index ]

Agora, se você fizer uma fatia [2:5]da lista acima, isso acontecerá:

        |           |
+---+---|---+---+---|---+
| P | Y | T | H | O | N |
+---+---|---+---+---|---+
  0   1 | 2   3   4 | 5

Você fez um corte antes do elemento com índice 2e outro corte antes do elemento com índice 5. Portanto, o resultado será uma fatia entre esses dois cortes, uma lista ['T', 'H', 'O'].

Jeyekomon
fonte
10

Pessoalmente, penso nisso como um forloop:

a[start:end:step]
# for(i = start; i < end; i += step)

Além disso, observe que os valores negativos para starte endsão relativos ao final da lista e computados no exemplo acima por given_index + a.shape[0].

Raman
fonte
8

A seguir, o exemplo de um índice de uma string:

 +---+---+---+---+---+
 | H | e | l | p | A |
 +---+---+---+---+---+
 0   1   2   3   4   5
-5  -4  -3  -2  -1

str="Name string"

Exemplo de fatia: [start: end: step]

str[start:end] # Items start through end-1
str[start:]    # Items start through the rest of the array
str[:end]      # Items from the beginning through end-1
str[:]         # A copy of the whole array

Abaixo está o exemplo de uso:

print str[0] = N
print str[0:2] = Na
print str[0:7] = Name st
print str[0:7:2] = Nm t
print str[0:-1:2] = Nm ti
Prince Dhadwal
fonte
5

Se você acha que os índices negativos no fatiamento são confusos, aqui está uma maneira muito fácil de pensar sobre isso: basta substituir o índice negativo por len - index. Por exemplo, substitua -3 por len(list) - 3.

A melhor maneira de ilustrar o que o fatiamento faz internamente é apenas mostrá-lo no código que implementa esta operação:

def slice(list, start = None, end = None, step = 1):
  # Take care of missing start/end parameters
  start = 0 if start is None else start
  end = len(list) if end is None else end

  # Take care of negative start/end parameters
  start = len(list) + start if start < 0 else start
  end = len(list) + end if end < 0 else end

  # Now just execute a for-loop with start, end and step
  return [list[i] for i in range(start, end, step)]
Shital Shah
fonte
4

A técnica básica de fatiar é definir o ponto de partida, o ponto de parada e o tamanho do passo - também conhecido como passada.

Primeiro, criaremos uma lista de valores para usar em nosso fatiamento.

Crie duas listas para fatiar. A primeira é uma lista numérica de 1 a 9 (Lista A). O segundo também é uma lista numérica, de 0 a 9 (Lista B):

A = list(range(1, 10, 1)) # Start, stop, and step
B = list(range(9))

print("This is List A:", A)
print("This is List B:", B)

Indexe o número 3 de A e o número 6 de B.

print(A[2])
print(B[6])

Fatiamento básico

A sintaxe de indexação estendida usada para fatiar é aList [start: stop: step]. O argumento inicial e o argumento da etapa assumem como padrão nenhum - o único argumento necessário é parar. Você percebeu que isso é semelhante ao modo como o intervalo foi usado para definir as listas A e B? Isso ocorre porque o objeto de fatia representa o conjunto de índices especificados pelo intervalo (iniciar, parar, etapa). Documentação do Python 3.4.

Como você pode ver, definir apenas stop retorna um elemento. Como o início não é padrão, isso significa recuperar apenas um elemento.

É importante notar que o primeiro elemento é o índice 0, não índice 1. É por isso que estamos usando 2 listas para este exercício. Os elementos da lista A são numerados de acordo com a posição ordinal (o primeiro elemento é 1, o segundo elemento é 2 etc.) enquanto os elementos da lista B são os números que seriam usados ​​para indexá-los ([0] para o primeiro elemento 0, etc.)

Com a sintaxe de indexação estendida, recuperamos um intervalo de valores. Por exemplo, todos os valores são recuperados com dois pontos.

A[:]

Para recuperar um subconjunto de elementos, as posições de início e parada precisam ser definidas.

Dado o padrão aList [start: stop], recupere os dois primeiros elementos da Lista A.

Babu Chandermani
fonte
3

Eu não acho que o diagrama tutorial do Python (citado em várias outras respostas) seja bom, pois essa sugestão funciona com passos positivos, mas não com passos negativos.

Este é o diagrama:

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

Do diagrama, espero a[-4,-6,-1]ser, yPmas é ty.

>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'

O que sempre funciona é pensar em caracteres ou slots e usar a indexação como um intervalo semiaberto - abertura à direita se for positivo, abertura à esquerda se for um passo negativo.

Dessa forma, eu posso pensar a[-4:-6:-1]como a(-6,-4]na terminologia de intervalo.

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

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