Понимание обозначения среза

3288

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

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

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

Саймон
источник

Ответы:

4510

Это довольно просто на самом деле:

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

Также есть stepзначение, которое можно использовать с любым из вышеперечисленных:

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

Ключевой момент, который следует запомнить, - это то, что :stopзначение представляет собой первое значение, которого нет в выбранном срезе. Таким образом, разница между stopи startявляется количеством выбранных элементов (если step1, по умолчанию).

Другая особенность заключается в том, что startили stopможет быть отрицательным числом, что означает, что оно отсчитывается от конца массива, а не от начала. Так:

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

Аналогично stepможет быть отрицательное число:

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 добр к программисту, если в нем меньше элементов, чем вы просите. Например, если вы запрашиваете a[:-2]и aсодержит только один элемент, вместо ошибки вы получите пустой список. Иногда вы бы предпочли ошибку, поэтому вы должны знать, что это может произойти.

Отношении slice() объекту

Оператор среза []фактически используется в приведенном выше коде с slice()объектом с использованием :нотации (которая действительна только внутри []), то есть:

a[start:stop:step]

эквивалентно:

a[slice(start, stop, step)]

Объекты среза также ведут себя немного по-разному в зависимости от количества аргументов, аналогично range(), то есть оба slice(stop)и slice(start, stop[, step])поддерживаются. Чтобы пропустить указание заданного аргумента, можно использовать None, например a[start:], эквивалентно a[slice(start, None)]или a[::-1]эквивалентно a[slice(None, None, -1)].

Хотя :нотация на основе очень полезна для простого среза, явное использование slice()объектов упрощает программную генерацию среза.

Грег Хьюгилл
источник
122
Нарезка встроенных типов возвращает копию, но это не универсально. Примечательно, что нарезка массивов NumPy возвращает представление, которое разделяет память с оригиналом.
Бени Чернявский-Паскин
43
Это красивый ответ с голосами, чтобы доказать это, но он упускает одну вещь: вы можете заменить Noneлюбое из пустых мест. Например [None:None]делает целую копию. Это полезно, когда вам нужно указать конец диапазона, используя переменную, и вам нужно включить последний элемент.
Марк Рэнсом
6
Что меня действительно раздражает, так это то, что python говорит, что когда вы не устанавливаете начало и конец, они по умолчанию равны 0 и длине последовательности. Итак, теоретически, когда вы используете «abcdef» [:: - 1], оно должно быть преобразовано в «abcdef» [0: 6: -1], но эти два выражения не получают одинаковый вывод. Я чувствую, что чего-то не хватает в документации Python с момента создания языка.
axell13
6
И я знаю, что «abcdef» [:: - 1] преобразуется в «abcdef» [6: -7: -1], поэтому лучший способ объяснить это так: пусть len будет длиной последовательности. Если шаг положительный , значения по умолчанию для начала и конца - 0 и длина . Иначе, если шаг отрицателен , значения по умолчанию для начала и конца - len и - len - 1.
axell13
4
Так как stackoverflow.com/questions/39241529/… помечен как дублирование этого, имеет ли смысл добавлять раздел с тем, что delделает запись нотации. В частности, del arr[:]не сразу очевидно («arr [:] делает копию, поэтому удаляет эту копию ???» и т. Д.)
хаджык,
538

Об этом рассказывается в руководстве по Python (прокрутите немного вниз, пока не дойдете до части о нарезке).

Рисунок ASCII также полезен для запоминания работы срезов:

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

Один из способов помнить, как работают срезы, - рассматривать индексы как указывающие между символами, причем левый край первого символа пронумерован 0. Тогда правый край последнего символа строки из n символов имеет индекс n .

Ганс Новак
источник
10
Это предложение работает для положительного шага, но не для отрицательного шага. Из диаграммы, я ожидаю , a[-4,-6,-1]чтобы быть , yPно это ty. То, что всегда работает, - это думать в символах или слотах и ​​использовать индексирование как полуоткрытый интервал - справа, если положительный шаг, или слева, если отрицательный шаг.
aguadopd
Но нет способа свернуть до пустого набора, начиная с конца (как это x[:0]происходит при запуске с начала), поэтому вам придется использовать специальные массивы для небольших случаев. : /
эндолиты
412

Перечисляя возможности, допускаемые грамматикой:

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

Конечно, если (high-low)%stride != 0, тогда конечная точка будет немного ниже, чем high-1.

Если strideотрицательный, порядок немного меняется, так как мы ведем обратный отсчет:

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

Расширенные срезы (с запятыми и эллипсами) в основном используются только специальными структурами данных (например, NumPy); основные последовательности не поддерживают их.

>>> class slicee:
...     def __getitem__(self, item):
...         return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
ephemient
источник
На самом деле, все еще есть что-то, например, если я наберу 'apple' [4: -4: -1] я получу 'elp', python переводит -4 в 1, может быть?
Liyuan
обратите внимание, что обратные пометки устарели в пользуrepr
wjandrea
@liyuan Тип реализации __getitem__является; ваш пример эквивалентен apple[slice(4, -4, -1)].
19
320

Ответы выше не обсуждают назначение срезов. Чтобы понять назначение срезов, полезно добавить еще одну концепцию в искусство 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']

Одна эвристика, для среза от нуля до n, подумайте: «ноль - это начало, начните с начала и возьмите n элементов в списке».

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

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

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

Первое правило назначения срезов заключается в том, что, поскольку срезы возвращают список, для назначения срезов требуется список (или другие итерируемые):

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

Второе правило назначения слайсов, которое вы также можете видеть выше, заключается в том, что любая часть списка, возвращаемая при индексации слайсов, это та же самая часть, которая изменяется при назначении слайсов:

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

Третье правило назначения слайсов состоит в том, что назначенный список (повторяемый) не должен иметь одинаковую длину; Индексированный фрагмент просто вырезается и заменяется массой на все, что ему назначено:

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

Самая хитрая часть, к которой нужно привыкнуть, - это назначение пустым слайсам. Используя эвристику 1 и 2, легко разобраться с индексированием пустого фрагмента:

>>> 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 = ['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

Обратите внимание, что, поскольку мы не меняем второе число среза (4), вставленные элементы всегда располагаются прямо напротив «o», даже когда мы назначаем пустой срез. Таким образом, позиция для пустого назначения среза является логическим расширением позиций для непустых назначений среза.

Немного резервного копирования, что произойдет, если вы продолжите нашу процессию подсчета начала среза?

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

С нарезкой, как только вы закончите, вы закончите; это не начинает разрезать назад. В Python вы не получите отрицательных шагов, если вы явно не попросите их, используя отрицательное число.

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

Есть несколько странных последствий для правила «как только вы закончите, вы закончите»:

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

Фактически, по сравнению с индексированием, нарезка Python причудливо защищена от ошибок:

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

Иногда это может пригодиться, но также может привести к несколько странному поведению:

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

В зависимости от вашего приложения это может ... или не может ... быть тем, на что вы надеялись!


Ниже приведен текст моего оригинального ответа. Это было полезно для многих людей, поэтому я не хотел его удалять.

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

Это также может прояснить разницу между нарезкой и индексацией.

Дэвид М. Перлман
источник
246

Объясните обозначение среза Python

Короче говоря, колоны ( :) в индексном обозначении ( subscriptable[subscriptarg]) делает срез обозначение - у которого есть необязательные аргументы, start, stop, step:

sliceable[start:stop:step]

Python Slice - это вычислительно быстрый способ для методического доступа к частям ваших данных. На мой взгляд, чтобы быть даже программистом среднего уровня на Python, это один из аспектов языка, с которым необходимо быть знакомым.

Важные определения

Для начала давайте определимся с несколькими терминами:

start: начальный индекс среза, он будет включать в себя элемент с этим индексом, если он не совпадает со стопом , по умолчанию равен 0, т.е. первый индекс. Если оно отрицательное, это значит начинать nпредметы с конца.

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

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

Как работает индексирование

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

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

Как работает нарезка

Чтобы использовать нотацию среза с последовательностью, которая ее поддерживает, необходимо включить хотя бы одно двоеточие в квадратные скобки, которые следуют за последовательностью (которые фактически реализуют __getitem__метод последовательности, согласно модели данных Python ).

Запись среза работает следующим образом:

sequence[start:stop:step]

И помните, что есть настройки по умолчанию для запуска , остановки и шага , поэтому для доступа к значениям по умолчанию просто пропустите аргумент.

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

my_list[-9:]

Когда я вижу это, я читаю часть в скобках как «9-е от конца до конца». (На самом деле, я мысленно сокращаю это как "-9, на")

Объяснение:

Полная запись

my_list[-9:None:None]

и подставить значения по умолчанию ( на самом деле , когда stepотрицательный, stopпо умолчанию имеет значение -len(my_list) - 1, поэтому Noneдля остановки на самом деле просто означает , что он идет в зависимости от того , конечный шаг берет его к):

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

Толстой кишки , :является то , что говорит Python , что вы даете ему кусочек , а не регулярный индекс. Вот почему идиоматический способ создания мелкой копии списков в Python 2

list_copy = sequence[:]

И очистка их с:

del my_list[:]

(Python 3 получает list.copyиlist.clear метод.)

Когда stepотрицательно, значения по умолчанию для startиstop изменить

По умолчанию, когда stepаргумент пуст (или None), он присваивается+1 .

Но вы можете передать отрицательное целое число, и список (или большинство других стандартных разрезаемых элементов) будет разрезан от конца до начала.

Таким образом, отрицательный срез изменит значения по умолчанию для startи stop!

Подтверждая это в источнике

Мне нравится поощрять пользователей читать как источник, так и документацию. Исходный код ломтика объекты и эта логика здесь . Сначала мы определяем, stepявляется ли оно отрицательным:

 step_is_negative = step_sign < 0;

Если это так, нижняя граница -1 означает, что мы нарезаем весь путь вплоть до начала, а верхняя граница - это длина минус 1, что означает, что мы начинаем с конца. (Обратите внимание , что семантика этого -1является отличается от А , -1что пользователи могут переходить индексы в Python , указывающие на последний элемент.)

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

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

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

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

Затем нам может потребоваться применить значения по умолчанию для startи stop- значение по умолчанию для for startрассчитывается как верхняя граница, когда stepона отрицательна:

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

и stopнижняя граница:

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

Дайте своим кусочкам описательное имя!

Может оказаться полезным отделить формирование среза от передачи его list.__getitem__методу (это то, что делают квадратные скобки ). Даже если вы не новичок в этом, он делает ваш код более читабельным, чтобы другие, которым, возможно, придется читать ваш код, могли более легко понять, что вы делаете.

Однако вы не можете просто присвоить переменной целые числа, разделенные двоеточиями. Вам нужно использовать объект среза:

last_nine_slice = slice(-9, None)

Второй аргумент, Noneобязателен, так что первый аргумент интерпретируется как startаргумент, иначе это будет stopаргумент .

Затем вы можете передать объект слайса в вашу последовательность:

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

Интересно, что диапазоны также берут кусочки:

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

Вопросы памяти:

Так как фрагменты списков Python создают новые объекты в памяти, следует помнить о другой важной функции itertools.islice. Обычно вам нужно перебирать фрагмент, а не просто создавать его статически в памяти. isliceидеально подходит для этого. Протест, он не поддерживает отрицательные аргументы start, stopили step, так что если это вопрос , вам могут понадобиться для расчета индексов или реверсом итерации заранее.

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

и сейчас:

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

Тот факт, что срезы списков делают копию, является особенностью самих списков. Если вы нарезаете сложные объекты, такие как Pandas DataFrame, он может вернуть представление оригинала, а не его копию.

Аарон Холл
источник
147

И пара вещей, которые не были сразу очевидны для меня, когда я впервые увидел синтаксис среза:

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

Простой способ изменить последовательность!

И если вы хотите, по какой-то причине, каждый второй элемент в обратной последовательности:

>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]
Dana
источник
100

В Python 2.7

Нарезка в 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).

Понимание назначения индекса очень важно.

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

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

Когда вы говорите [a: b: c], вы говорите, в зависимости от знака c (вперед или назад), начинайте с a и заканчивайте на b (исключая элемент с индексом b). Используйте вышеприведенное правило индексации и помните, что вы найдете только элементы в этом диапазоне:

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

Но этот диапазон продолжается в обоих направлениях бесконечно:

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

Например:

             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

Если ваш выбор a, b и c позволяет перекрываться с указанным выше диапазоном, когда вы проходите, используя правила для a, b, c выше, вы либо получите список с элементами (затронутый во время обхода), либо вы получите пустой список.

И последнее: если a и b равны, вы также получаете пустой список:

>>> 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]
Анкур Агарвал
источник
2
еще один интересный пример: a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]который приводит к[9]
Deviacium
96

Нашел эту великолепную таблицу по адресу 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
источник
65

После небольшого использования я понимаю, что самое простое описание - это то же самое, что и аргументы в forцикле ...

(from:to:step)

Любые из них являются необязательными:

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

Тогда для отрицательного индексирования нужно, чтобы вы добавили длину строки к отрицательным индексам, чтобы понять это.

В любом случае это работает для меня ...

Саймон
источник
52

Мне легче вспомнить, как это работает, и затем я могу определить любую конкретную комбинацию старт / стоп / шаг.

Поучительно range()сначала понять :

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

Начните с start, увеличивайте step, не достигайте stop. Очень просто.

О негативном шаге следует помнить, что stopэто всегда исключаемый конец, будь то выше или ниже. Если вы хотите, чтобы один и тот же срез находился в обратном порядке, гораздо проще сделать инверсию по отдельности: например, 'abcde'[1:-2][::-1]срезать один символ слева, два справа, а затем поменять местами. (Смотри также reversed().)

Секвенция секвенции такая же, за исключением того, что сначала она нормализует отрицательные индексы и никогда не может выходить за пределы последовательности:

TODO : В приведенном ниже коде была ошибка «никогда не выходить за пределы последовательности», когда abs (step)> 1; Я думаю, что я исправил это, чтобы быть правильным, но это трудно понять.

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]

Не беспокойтесь о is Noneдеталях - просто помните, что опускание startи / или stopвсегда делает правильные вещи, чтобы дать вам всю последовательность.

Нормализация отрицательных индексов сначала позволяет независимо начинать и / или останавливать отсчет с конца: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'несмотря на range(1,-2) == []. Нормализация иногда рассматривается как «по модулю длины», но обратите внимание, что она добавляет длину только один раз: например, 'abcde'[-53:42]это просто целая строка.

Бени Чернявский-Паскин
источник
3
Это this_is_how_slicing_worksне то же самое, что срез питона. EG [0, 1, 2][-5:3:3]получит [0] в python, но list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))получит [1].
Eastsun
@Eastsun Ой, ты прав! Более понятный случай: range(4)[-200:200:3] == [0, 3]но list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]. Моя if 0 <= i < len(seq):попытка реализовать «никогда не выходить за пределы последовательности» просто, но не подходит для шага> 1. Я перепишу это позже сегодня (с тестами).
Бени Чернявский-Паскин
40

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

mylist[X:Y]

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

Стив Лош
источник
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   :
|--------------->
    <---------------|

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

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

Сиаою
источник
38

Обозначение среза Python:

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

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

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

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

nobar
источник
34

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

r = [1, 'blah', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]
dansalmo
источник
33

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

>>> 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]
Ариндам Ройчоудхури
источник
33

Вот как я преподаю ломтики новичкам:

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

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

Введите описание изображения здесь

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

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

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

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

Вы можете даже выбрать первые три блока или последние два блока или все блоки от 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]

Примечание. Этот пост изначально был написан в моем блоге «Интеллект за кусочками Python» .

ChillarAnand
источник
29

Как правило, написание кода с большим количеством жестко закодированных значений индекса приводит к беспорядку читаемости и обслуживания. Например, если вы вернетесь к коду год спустя, вы посмотрите на него и удивитесь, о чем вы думали, когда писали его. Показанное решение - просто способ более четко определить, что на самом деле делает ваш код. Как правило, встроенный 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
>>>
Python_Dude
источник
25

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

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

s[start:end:step]

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

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

Другой импорт вещь: все 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 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].

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

Делать вещи более запутанными - это stepтоже может быть негативно!

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

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

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

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

Будьте удивлены: слайс не вызывает ошибку IndexError, когда индекс выходит за пределы диапазона!

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

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. Примеры

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

# 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
источник
24

В предыдущих ответах не обсуждается разделение многомерных массивов, что возможно при использовании известного пакета 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» после запятой действует во втором измерении.

Statham
источник
4
Просто дружеское напоминание, что вы не можете сделать это на Python, listно только на arrayNumpy
Марс Ли
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)

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

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

mahmoh
источник
14

Мой мозг, кажется, рад принять, что lst[start:end]содержит start-й пункт. Я мог бы даже сказать, что это «естественное предположение».

Но иногда возникает сомнение, и мой мозг просит заверить, что он не содержит end-го элемента.

В эти моменты я полагаюсь на эту простую теорему:

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

Это симпатичное свойство говорит мне, что lst[start:end]не содержит end-й элемент, потому что он находится в lst[end:].

Обратите внимание, что эта теорема верна для любого nвообще. Например, вы можете проверить, что

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

возвращается True.

Роберт
источник
12

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

Давайте работать со следующей строкой ...

azString = "abcdefghijklmnopqrstuvwxyz"

Для тех, кто не знает, вы можете создать любую подстроку, azStringиспользуя обозначениеazString[x:y]

Исходя из других языков программирования, это когда здравый смысл нарушается. Что такое х и у?

Мне пришлось сесть и запустить несколько сценариев в своем поиске техники запоминания, которая поможет мне вспомнить, что такое x и y, и поможет мне правильно нарезать строки с первой попытки.

Мой вывод заключается в том, что x и y следует рассматривать как граничные индексы, которые окружают строки, которые мы хотим добавить. Таким образом, мы должны видеть выражение как azString[index1, index2]или даже более ясным, какazString[index_of_first_character, index_after_the_last_character] .

Вот пример визуализации этого ...

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

Поэтому все, что вам нужно сделать, это установить index1 и index2 в значения, которые будут окружать желаемую подстроку. Например, чтобы получить подстроку "cdefgh", вы можете использоватьazString[2:8] , потому что индекс слева от «c» равен 2, а индекс справа от «h» равен 8.

Помните, что мы устанавливаем границы. И эти границы - это позиции, где вы можете поместить несколько скобок, которые будут обернуты вокруг подстроки, как это ...

ab [ cdefgh ] ij

Этот трюк работает постоянно и его легко запомнить.

asiby
источник
11

Большинство предыдущих ответов проясняют вопросы о записи срезов.

Расширенный синтаксис индексации, используемый для нарезки aList[start:stop:step], и основные примеры:

Введите описание изображения здесь:

Больше примеров нарезки: 15 расширенных ломтиков

Рошан Багдия
источник
10

В Python наиболее простой формой для нарезки является следующее:

l[start:end]

где l- некоторая коллекция, startэто инклюзивный индекс и endэксклюзивный индекс.

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]

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

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

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

Отрицательные целые числа полезны при выполнении смещений относительно конца коллекции:

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]

Можно предоставить индексы, которые выходят за границы при нарезке, такие как:

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]

Имейте в виду, что результатом нарезки коллекции является совершенно новая коллекция. Кроме того, при использовании обозначений срезов в назначениях длина назначений срезов не обязательно должна быть одинаковой. Значения до и после назначенного среза будут сохранены, а коллекция будет уменьшаться или увеличиваться, чтобы содержать новые значения:

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]

Если вы пропустите начальный и конечный индексы, вы создадите копию коллекции:

In [14]: l_copy = l[:]

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

Если начальный и конечный индексы опущены при выполнении операции присваивания, весь контент коллекции будет заменен копией того, на что есть ссылки:

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

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

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

l[start:end:step]

где l- коллекция, startинклюзивный индекс, endэксклюзивный индекс и stepшаг, который можно использовать для ввода каждого n-го элемента 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]

Использование stepпредоставляет полезную хитрость для обращения коллекции в Python:

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

Также можно использовать отрицательные целые числа для stepследующего примера:

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

Однако использование отрицательного значения для stepможет стать очень запутанным. Кроме того, для того , чтобы быть вещим , следует избегать использования start, endи stepв одном срезе. В случае, если это требуется, подумайте о том, чтобы сделать это в двух заданиях (одно для нарезки, а другое для продвижения).

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
источник
10

Я хочу добавить один Hello, World! Пример, объясняющий основы ломтиков для самых начинающих. Это мне очень помогло.

Давайте составим список из шести значений ['P', 'Y', 'T', 'H', 'O', 'N']:

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

Теперь простейшими срезами этого списка являются его подсписки. Обозначение [<index>:<index>]и ключ, чтобы прочитать это так:

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

Теперь, если вы сделаете часть [2:5]списка выше, это произойдет:

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

Вы сделали разрез перед элементом с индексом 2и еще один разрез перед элементом с индексом 5. Таким образом, результатом будет срез между этими двумя разрезами, список ['T', 'H', 'O'].

Jeyekomon
источник
10

Я лично думаю об этом как о forпетле:

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

Также обратите внимание, что отрицательные значения для startи endотносятся к концу списка и вычисляются в приведенном выше примере с помощью given_index + a.shape[0].

Раман
источник
8

Ниже приведен пример индекса строки:

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

str="Name string"

Пример нарезки: [начало: конец: шаг]

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

Ниже приведен пример использования:

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
Принц дхадвал
источник
5

Если вы чувствуете, что отрицательные индексы в разрезании сбивают с толку, вот очень простой способ подумать об этом: просто замените отрицательный индекс на len - index. Так, например, заменить -3 на len(list) - 3.

Лучший способ проиллюстрировать, что секционирование выполняет внутренне, - просто показать это в коде, который реализует эту операцию:

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)]
Шиталь шах
источник
4

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

Во-первых, мы создадим список значений для использования в нашей нарезке.

Создайте два списка для нарезки. Первый представляет собой числовой список от 1 до 9 (список А). Второй также является числовым списком от 0 до 9 (список 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)

Индексируйте число 3 от A и число 6 от B.

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

Базовая нарезка

Расширенный синтаксис индексации, используемый для нарезки, - это aList [start: stop: step]. Аргумент start и шаг по умолчанию равны none - единственным обязательным аргументом является stop. Вы заметили, что это похоже на то, как диапазон использовался для определения списков A и B? Это связано с тем, что объект слайса представляет собой набор индексов, заданных диапазоном (начало, остановка, шаг). Документация по Python 3.4.

Как видите, определение только stop возвращает один элемент. Поскольку в начале по умолчанию ничего нет, это приводит к извлечению только одного элемента.

Важно отметить, что первым элементом является индекс 0, а не индекс 1. Именно поэтому мы используем 2 списка для этого упражнения. Элементы списка A нумеруются в соответствии с порядковым положением (первый элемент равен 1, второй элемент равен 2 и т. Д.), А элементы списка B представляют собой числа, которые будут использоваться для их индексации ([0] для первого элемента 0, так далее.).

С расширенным синтаксисом индексации мы получаем диапазон значений. Например, все значения извлекаются с помощью двоеточия.

A[:]

Чтобы получить подмножество элементов, необходимо определить начальную и конечную позиции.

Учитывая шаблон aList [start: stop], получить первые два элемента из списка А.

Бабу Чандермани
источник
3

Я не думаю, что учебная схема Python (цитируемая в различных других ответах) хороша, так как это предложение работает для положительного шага, но не для отрицательного шага.

Это диаграмма:

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

Из диаграммы, я ожидаю , a[-4,-6,-1]чтобы быть , yPно это ty.

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

То, что всегда работает, - это думать в символах или слотах и ​​использовать индексирование как полуоткрытый интервал - справа, если положительный шаг, или слева, если отрицательный шаг

Таким образом, я могу думать , a[-4:-6:-1]как a(-6,-4]в интервальной терминологии.

 +---+---+---+---+---+---+
 | 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
источник