Understanding slice notation
Мне нужно хорошее объяснение (ссылки плюс) на нотации среза Python.
Мне эта запись нуждается в небольшом подборе.
Это выглядит очень мощно, но я не совсем понял, где это.
41 ответ
Это довольно просто на самом деле:
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
количество выбранных элементов (если step
1, по умолчанию).
Другая особенность заключается в том, что 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()
Объекты упрощает программную генерацию нарезки.
Об этом рассказывается в руководстве по Python (прокрутите немного вниз, пока не дойдете до части о нарезке).
Диаграмма ASCII также полезна для запоминания работы срезов:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
Один из способов помнить, как работают срезы, - рассматривать индексы как указывающие между символами, причем левый край первого символа нумеруется 0. Тогда правый край последнего символа строки из n символов имеет индекс n.
Перечисляя возможности, допускаемые грамматикой:
>>> 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 `item`
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
Ответы выше не обсуждают назначение срезов. Чтобы понять назначение срезов, полезно добавить еще одну концепцию к искусству 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]
Это также может прояснить разницу между нарезкой и индексацией.
Объясните обозначение среза 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]
И помните, что существуют значения по умолчанию для 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
- по умолчанию тогда для 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, он может вернуть представление оригинала, а не его копию.
И несколько вещей, которые не были сразу очевидны для меня, когда я впервые увидел синтаксис среза:
>>> 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]
В 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]
Нашел эту отличную таблицу на 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)
После небольшого использования я понимаю, что самое простое описание - это то же самое, что и аргументы в for
петля...
(from:to:step)
Любой из них не является обязательным:
(:to:step)
(from::step)
(from:to)
Тогда для отрицательного индексирования нужно, чтобы вы добавили длину строки к отрицательным индексам, чтобы понять это.
В любом случае это работает для меня...
Мне легче вспомнить, как это работает, затем я могу определить любую конкретную комбинацию старт / стоп / шаг.
Поучительно понимать 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]
это просто целая строка.
Я сам использую метод "индексных точек между элементами", чтобы думать об этом сам, но один способ описать его, который иногда помогает другим получить его, заключается в следующем:
mylist[X:Y]
X - это индекс первого элемента, который вы хотите.
Y - индекс первого элемента, который вам не нужен.
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
Вот как я преподаю ломтики новичкам:
Понимание разницы между индексированием и нарезкой:
У Wiki Python есть эта удивительная картина, которая четко различает индексацию и нарезку.
Это список из 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
Нотация Python:
a[start:end:step]
- За
start
а такжеend
отрицательные значения интерпретируются как относящиеся к концу последовательности. - Положительные показатели для
end
указать позицию после последнего элемента, который будет включен. - Пустые значения по умолчанию следующие:
[+0:-0:1]
, - Использование отрицательного шага меняет интерпретацию
start
а такжеend
Обозначения распространяются на (numpy) матрицы и многомерные массивы. Например, чтобы разрезать целые столбцы, вы можете использовать:
m[::,0:2:] ## slice the first two columns
Срезы содержат ссылки, а не копии элементов массива. Если вы хотите сделать отдельную копию массива, вы можете использовать deepcopy()
,
Вы также можете использовать назначение слайса, чтобы удалить один или несколько элементов из списка:
r = [1, 'blah', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]
Это просто для дополнительной информации... Рассмотрим список ниже
>>> 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]
Смотрите ответ ABC выше
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 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
Как правило, написание кода с большим количеством жестко закодированных значений индекса приводит к беспорядку читаемости и обслуживания. Например, если вы вернетесь к коду год спустя, вы посмотрите на него и удивитесь, о чем вы думали, когда писали его. Показанное решение - просто способ более четко определить, что на самом деле делает ваш код. Как правило, встроенный 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 >>>
Ответы выше не обсуждают многомерный срез массива, который возможен при использовании известного пакета 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" после запятой действует во втором измерении.
Правила нарезки следующие:
[lower bound : upper bound : step size]
I- Конвертироватьupper bound
а также lower bound
в общие знаки.
II- Затем проверьте,step size
- положительное или отрицательное значение.
(i) Еслиstep size
является положительной величиной,upper bound
должно быть больше чем lower bound
, иначе empty string
печатается. Например:
s="Welcome"
s1=s[0:3:1]
print(s1)
Выход:
Wel
Однако, если мы запустим следующий код:
s="Welcome"
s1=s[3:0:1]
print(s1)
Он вернет пустую строку.
(ii) Еслиstep size
если отрицательное значение,upper bound
должно быть меньше чем lower bound
, иначе empty string
будут напечатаны. Например:
s="Welcome"
s1=s[3:0:-1]
print(s1)
Выход:
cle
Но если мы запустим следующий код:
s="Welcome"
s1=s[0:5:-1]
print(s1)
Результатом будет пустая строка.
Таким образом в коде:
str = 'abcd'
l = len(str)
str2 = str[l-1:0:-1] #str[3:0:-1]
print(str2)
str2 = str[l-1:-1:-1] #str[3:-1:-1]
print(str2)
Во-первых str2=str[l-1:0:-1]
, то upper bound
это меньше, чемlower bound
, таким образом dcb
печатается.
Однако в str2=str[l-1:-1:-1]
, то upper bound
является не менееlower bound
(при преобразовании lower bound
в отрицательное значение, которое-1
: поскольку index
последнего элемента равно -1, как и 3).
Хехехе, странно видеть себя пытающимся дать лучшее и более простое объяснение после 2600+ голосов по поводу того, что было отмечено как правильный ответ от Грю Хьюгилла.
Вот так...
На мой взгляд, вы лучше поймете и запомните нотацию 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]
потому что индекс слева "с" равен 2, а индекс справа "h" равен 8.
Помните, мы устанавливаем границы.
Этот трюк работает постоянно и его легко запомнить.
Надеюсь, это поможет.
Я лично думаю об этом как цикл
a[start:end:step]
# for(i = start; i < end; i += step)
Также обратите внимание, что отрицательные значения для start
а также end
относительно конца списка.
#!/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.
Мой мозг, кажется, рад принять это 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
,
В 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 3 elements
Out[8]: [7, 8, 9]
Можно предоставить индексы, которые выходят за границы при нарезке, такие как:
In [9]: l[:20] # 20 is out of index bounds, 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, 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 less 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
может стать очень запутанным. Кроме того, чтобы быть Pythonic, вы должны избегать использования 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]
Я хочу добавить один пример 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']
,
Чтобы получить определенный фрагмент итерируемого (например, списка), вот пример:
variable[number1:number2]
В этом примере положительное число для числа 1 - это количество компонентов, которые вы снимаете с фронта. Отрицательное число - это полная противоположность тому, сколько вы держите до конца. Положительное число для числа 2 указывает, сколько компонентов вы собираетесь оставить с самого начала, а отрицательное - сколько вы собираетесь снять с конца. Это несколько противоречит интуиции, но вы правы, полагая, что нарезка списка чрезвычайно полезна.
Большинство из приведенных выше ответов проясняется относительно обозначения слайса. Расширенный синтаксис индексации, используемый для нарезки aList[start:stop:step]
основные примеры
Больше примеров нарезки: 15 расширенных срезов
Важная идея, которую следует помнить об индексах последовательности, состоит в том, что
- неотрицательные индексы начинаются с первого элемента последовательности;
- отрицательные индексы начинаются с последнего элемента в последовательности (поэтому применяются только к конечным последовательностям).
Другими словами, отрицательные индексы сдвигаются вправо на длину последовательности:
0 1 2 3 4 5 6 7 ...
-------------------------
| a | b | c | d | e | f |
-------------------------
... -8 -7 -6 -5 -4 -3 -2 -1
Имея это в виду, подписка и нарезка просты.
Подписка
Подписка использует следующий синтаксис:*
sequence[index]
Подписка выбирает один элемент в at :
>>> 'abcdef'[0]
'a'
>>> 'abcdef'[-6]
'a'
Подписка повышает
index
что вне диапазона:
>>> 'abcdef'[100]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
Нарезка
Нарезка использует следующий синтаксис:**
sequence[start:stop:step]
Нарезка выбирает диапазон элементов в , начиная с включительно и заканчивая эксклюзивно:
>>> 'abcdef'[0:2:1]
'ab'
>>> 'abcdef'[0:-4:1]
'ab'
>>> 'abcdef'[-6:-4:1]
'ab'
>>> 'abcdef'[-6:2:1]
'ab'
>>> 'abcdef'[1:-7:-1]
'ba'
>>> 'abcdef'[-5:-7:-1]
'ba'
Нарезка по умолчанию включает самый полный диапазон элементов в
sequence
, поэтому он использует следующие значения по умолчанию для любых , , или которые опущены или равны
None
:***
- по умолчанию
1
; - если положительный
- по умолчанию
0
(индекс первого элемента), - по умолчанию
start + len(sequence)
(последний индекс элемента плюс один);
- по умолчанию
- если отрицательно
- по умолчанию
-1
(последний индекс элемента), - по умолчанию
start - len(sequence)
(первый индекс элемента минус один).
- по умолчанию
>>> 'abcdef'[0:6:1]
'abcdef'
>>> 'abcdef'[::]
'abcdef'
>>> 'abcdef'[-1:-7:-1]
'fedcba'
>>> 'abcdef'[::-1]
'fedcba'
Нарезка поднимает
ValueError
для a, равного нулю:
>>> 'abcdef'[::0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: slice step cannot be zero
Нарезка не вызывает
IndexError
для или вне допустимого диапазона (вопреки подписке):
>>> 'abcdef'[-100:100]
'abcdef'
* Выражения
sequence[index]
а также
sequence.__getitem__(index)
эквивалентны.
** Выражения
sequence[start:stop:step]
,
sequence[slice(start, stop, step)]
, а также
sequence.__getitem__(slice(start, stop, step))
эквивалентны, где встроенный класс
slice
пакеты экземпляров , и .
*** Выражения
sequence[:]
,
sequence[::]
, а также
sequence[None:None:None]
использовать значения по умолчанию для
start
,
stop
, а также
step
.
Ниже приведен пример индекса строки
+---+---+---+---+---+
| 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