Понимание обозначения среза - PullRequest
2785 голосов
/ 04 февраля 2009

Мне нужно хорошее объяснение (ссылки плюс) на нотации Python.

Мне эта запись нуждается в небольшом подборе.

Выглядит очень мощно, но я не совсем понял, где это.

Ответы [ 31 ]

36 голосов
/ 04 февраля 2013
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   :
|--------------->
    <---------------|

Надеюсь, это поможет вам смоделировать список в Python.

Ссылка: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

35 голосов
/ 07 февраля 2009

Я сам использую метод «указатель указывает между элементами», но один способ описать его, который иногда помогает другим получить его, заключается в следующем:

mylist[X:Y]

X - это индекс первого элемента, который вы хотите.
Y - индекс первого элемента, который вы не хотите.

34 голосов
/ 28 апреля 2013

Нотация Python:

a[start:end:step]
  • Для start и end отрицательные значения интерпретируются как относящиеся к концу последовательности.
  • Положительные индексы для end указывают позицию после последнего включаемого элемента.
  • Пустые значения по умолчанию следующие: [+0:-0:1].
  • Использование отрицательного шага переворачивает интерпретацию start и end

Обозначения распространяются на (пустые) матрицы и многомерные массивы. Например, чтобы разрезать столбцы целиком, вы можете использовать:

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

Срезы содержат ссылки, а не копии элементов массива. Если вы хотите сделать отдельную копию массива, вы можете использовать deepcopy().

31 голосов
/ 24 марта 2015

Вот как я учу новичков ломтикам:

Понимание разницы между индексированием и нарезкой:

В Wiki Python есть удивительная картинка, которая четко различает индексирование и нарезку.

enter image description here

Это список из 6 элементов. Чтобы лучше понять нарезку, рассмотрите этот список как набор из шести блоков, помещенных вместе. В каждой коробке есть алфавит.

Индексирование похоже на работу с содержимым коробки. Вы можете проверить содержимое любого ящика. Но Вы не можете проверить содержимое нескольких ящиков одновременно. Вы даже можете заменить содержимое коробки. Но Вы не можете поместить 2 шара в 1 коробку или заменить 2 шара одновременно.

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

Нарезка подобна работе с самими коробками. Вы можете забрать первую коробку и поставить ее на другой стол. Чтобы поднять коробку, вам нужно знать только положение начала и конца коробки.

Вы можете даже забрать первые 3 ящика или последние 2 ящика или все ящики между 1 и 4. Таким образом, Вы можете выбрать любой набор ящиков, если знаете начало и конец. Эти позиции называются стартовой и стоповой позициями.

Интересно то, что вы можете заменить несколько ящиков одновременно. Также Вы можете разместить несколько ящиков в любом месте.

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

Нарезка с шагом:

До сих пор Вы постоянно выбирали ящики. Но иногда вам нужно забрать дискретно. Например, вы можете забрать каждую вторую коробку. Вы можете даже забрать каждую третью коробку с конца. Это значение называется размером шага. Это представляет собой разрыв между вашими последовательными пикапами. Размер шага должен быть положительным, если вы выбираете поля от начала до конца и наоборот.

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

Как Python вычисляет недостающие параметры:

При разрезании, если вы пропускаете какой-либо параметр, Python пытается выяснить это автоматически.

Если вы проверите исходный код CPython, вы найдете функцию PySlice_GetIndicesEx, которая вычисляет индексы для среза для любых заданных параметров. Вот логический эквивалентный код в Python.

Эта функция принимает объект Python и необязательные параметры для нарезки и возвращает начальный, конечный, шаг и длину среза для запрошенного среза.

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)

Это интеллект, который присутствует за кусочками. Поскольку в Python есть встроенная функция, называемая slice, вы можете передать некоторые параметры и проверить, насколько разумно он рассчитывает отсутствующие параметры.

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]

Примечание: Это сообщение изначально написано в моем блоге http://www.avilpage.com/2015/03/a-slice-of-python-intelligence-behind.html

30 голосов
/ 05 апреля 2013

Вы также можете использовать назначение слайса, чтобы удалить один или несколько элементов из списка:

r = [1, 'blah', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]
30 голосов
/ 22 марта 2012

Это просто дополнительная информация ... Рассмотрим список ниже

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

Несколько других трюков для изменения списка:

>>> 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]
26 голосов
/ 07 декабря 2013

Как правило, написание кода с большим количеством жестко закодированных значений индекса обеспечивает читабельность и обслуживание беспорядок. Например, если вы вернетесь к коду год спустя, вы посмотрите на это и удивитесь, о чем вы думали, когда писали это. Решение показано это просто способ более четко заявить, что на самом деле делает ваш код. Как правило, встроенный slice () создает объект слайса, который можно использовать в любом месте слайса. позволено. Например:

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

Если у вас есть экземпляр среза s, вы можете получить больше информации о нем, посмотрев его Атрибуты s.start, s.stop и s.step соответственно. Например:

>>> a = slice(10, 50, 2)
>>> a.start
10
>>> a.stop
50
>>> a.step
2
>>>
25 голосов
/ 09 января 2017

1. Обозначение среза

Чтобы упростить задачу, помните, срез имеет только одну форму:

s[start:end:step]

и вот как это работает:

  • s: объект, который можно нарезать
  • start: первый индекс для начала итерации
  • end: последний индекс, ОБРАТИТЕ ВНИМАНИЕ, что индекс end не будет включен в результирующий фрагмент
  • step: выбор элемента каждые step индекс

Еще одна вещь импорта: all start, end, step может быть опущено! И если они опущены, будет использовано их значение по умолчанию: 0, len(s), 1 соответственно.

Возможны следующие варианты:

# 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[:]

ПРИМЕЧАНИЕ: Если start>=end (учитывая только когда step>0), python вернет пустой срез [].

2. Ловушки

Вышеприведенная часть объясняет основные функции того, как работает слайс, он будет работать в большинстве случаев. Однако могут быть подводные камни, на которые следует обратить внимание, и эта часть объясняет их.

Отрицательные показатели

Самое первое, что смущает изучающих Python, это то, что индекс может быть отрицательным! Не паникуйте: отрицательный индекс означает отсчет назад.

Например:

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

Отрицательный шаг

Еще более запутанно то, что step тоже может быть отрицательным!

Отрицательный шаг означает итерацию массива в обратном направлении: от конца к началу, с включенным индексом конца и без индекса начала из результата.

ПРИМЕЧАНИЕ : если шаг отрицательный, значение по умолчанию от start до len(s) (тогда как end не равно 0, поскольку s[::-1] содержит s[0]). Например:

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

Ошибка вне диапазона?

Удивляйтесь: слайс не вызывает IndexError, когда индекс выходит за пределы диапазона!

Если индекс выходит за пределы диапазона, python будет стараться изо всех сил установить индекс на 0 или len(s) в зависимости от ситуации. Например:

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

3. Примеры

Давайте закончим этот ответ примерами, объясняющими все, что мы обсуждали:

# 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, 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 IndexError
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]

IndexError: list index out of range
19 голосов
/ 01 марта 2017

Ответы выше не обсуждают нарезку многомерных массивов, что возможно при использовании известного пакета NumPy:

Нарезка также может применяться к многомерным массивам.

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

":2" перед запятой действует на первое измерение, а "0:3:2" после запятой действует на второе измерение.

13 голосов
/ 18 октября 2014
#!/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)

Вы можете запустить этот скрипт и поэкспериментировать с ним, ниже приведены некоторые примеры, которые я получил из скрипта.

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

При использовании отрицательного шага обратите внимание, что ответ смещен вправо на 1.

...