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

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

На мой взгляд, это обозначение требует некоторого уточнения.

Он выглядит чрезвычайно мощным, но я не совсем понимаю.


person Simon    schedule 03.02.2009    source источник


Ответы (33)


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

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

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

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

person Greg Hewgill    schedule 03.02.2009
comment
Нарезка встроенных типов возвращает копию, но это не универсально. В частности, нарезка массивов NumPy возвращает представление, которое разделяет память с оригинал. - person Beni Cherniavsky-Paskin; 23.09.2013
comment
Это красивый ответ с голосами, подтверждающими его, но он упускает одну вещь: вы можете заменить None на любое пустое пространство. Например, [None:None] делает копию целиком. Это полезно, когда вам нужно указать конец диапазона с помощью переменной и включить последний элемент. - person Mark Ransom; 16.01.2019
comment
Обратите внимание, что, в отличие от обычных фрагментов Python (см. Выше), в Pandas Dataframes как начало, так и остановка включены, если они присутствуют в индексе. Для получения дополнительной информации см. документацию по индексированию Pandas.. - person vreyespue; 29.05.2019
comment
Что меня действительно раздражает, так это то, что python говорит, что, когда вы не устанавливаете начало и конец, они по умолчанию равны 0 и длине последовательности. Итак, теоретически, когда вы используете abcdef [:: - 1], он должен быть преобразован в abcdef [0: 6: -1], но эти два выражения не дают одинаковых результатов. Мне кажется, что с момента создания языка в документации Python чего-то не хватает. - person axell-brendow; 30.06.2019
comment
И я знаю, что abcdef [:: - 1] преобразуется в abcdef [6: -7: -1], поэтому лучший способ объяснить это: пусть len будет длиной последовательности . Если шаг положительный, значения по умолчанию для начала и конца - 0 и len. Иначе, если шаг отрицательный, значения по умолчанию для начала и конца равны len и - len - 1. - person axell-brendow; 30.06.2019
comment
Довольно интересно, что третий шаг или аргумент шага был более поздним добавочным срезом [start: stop: stride] docs.python.org/2.3/whatsnew/section-slices.html - person gaoithe; 26.01.2021
comment
a [-1] # последний элемент в массиве. Это единственный способ получить последний элемент с помощью нарезки? Похоже, что [-1:] не работает. Почему? - person James_; 23.05.2021
comment
Почему кажется, что start: stop находятся в неправильном порядке для них: 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 Я проверил на консоли iPython, что ваш ответ правильный, но, похоже, он не соответствует шагу start: stop:. Я бы подумал, что перевернуть первые два элемента было бы a[:2:-1] - person mLstudent33; 31.05.2021

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

Арт-диаграмма ASCII также полезна для запоминания того, как работают срезы:

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

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

person Hans Nowak    schedule 03.02.2009
comment
Это предложение работает для положительного шага, но не для отрицательного шага. Судя по диаграмме, я ожидаю, что a[-4,-6,-1] будет yP, но это ty. Что всегда работает, так это думать символами или слотами и использовать индексирование как полуоткрытый интервал - открывать вправо при положительном шаге, открывать влево при отрицательном шаге. - person aguadopd; 27.05.2019
comment
Но нет никакого способа свернуть до пустого набора, начиная с конца (как x[:0], начиная с начала), поэтому вам нужно использовать небольшие массивы для особых случаев. : / - person endolith; 06.07.2019
comment
@aguadopd Вы абсолютно правы. Решение состоит в том, чтобы сдвинуть индексы вправо, по центру под символами, и обратить внимание на то, что остановка всегда исключается. Смотрите другой ответ чуть ниже. - person Javier Ruiz; 06.04.2021
comment
Дополнение к моему комментарию: см. Мой ответ с диаграммами ниже: stackoverflow.com/a/56332104/2343869 - person aguadopd; 15.04.2021

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

>>> 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)'
person ephemient    schedule 03.02.2009
comment
На самом деле кое-что еще не учтено, например. если я наберу «яблоко» [4: -4: -1], я получаю «elp», возможно, python переводит -4 в 1? - person liyuan; 01.01.2018
comment
обратите внимание, что обратные кавычки устарели в пользу repr - person wjandrea; 27.01.2019
comment
@liyuan Тип реализации __getitem__: ваш пример эквивалентен apple[slice(4, -4, -1)]. - person chepner; 10.09.2019

Объясните нотацию фрагментов Python

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

sliceable[start:stop:step]

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

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

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

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

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

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

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

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

 +---+---+---+---+---+---+
 | 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, on)

Объяснение:

Полное обозначение

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, он может возвращать представление оригинала, а не копию.

person Aaron Hall    schedule 12.07.2014
comment
Мне нравится идея именовать срезы. Я бы предположил, что (start:stop) нотация вводит в заблуждение, и (start_at:stop_before) нотация, возможно, помешала мне найти эти вопросы и ответы. - person WinEunuuchs2Unix; 30.09.2020
comment
@ WinEunuuchs2Unix, отличная обратная связь - это стандартное поведение Python, но таким образом его можно было бы сделать более понятным, поэтому я рассмотрю возможность обновления моего материала, чтобы включить эту семантику. - person Aaron Hall; 30.09.2020

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

>>> 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]
person Dana    schedule 03.02.2009

В 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]
person Ankur Agarwal    schedule 22.10.2012
comment
еще один интересный пример: a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2] что приводит к [9] - person Deviacium; 10.07.2017

Нашел эту замечательную таблицу на 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)
person AdrianoFerrari    schedule 06.09.2011

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

(from:to:step)

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

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

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

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

person Simon    schedule 19.02.2009

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

Поучительно сначала понять 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().)

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

ЗАДАЧА. В приведенном ниже коде была ошибка "никогда не выходить за пределы последовательности", когда abs (шаг)> 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] - это всего лишь вся строка.

person Beni Cherniavsky-Paskin    schedule 29.03.2012
comment
this_is_how_slicing_works - это не то же самое, что фрагмент Python. НАПРИМЕР. [0, 1, 2][-5:3:3] получит [0] в python, но list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3)) получит [1]. - person Eastsun; 29.10.2016
comment
@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. Перепишу сегодня позже (с тестами). - person Beni Cherniavsky-Paskin; 30.10.2016

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

mylist[X:Y]

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

person Steve Losh    schedule 06.02.2009

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

person xiaoyu    schedule 04.02.2013

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

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

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

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

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

person Brent Bradburn    schedule 28.04.2013

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

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

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

person ChillarAnand    schedule 24.03.2015

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

r = [1, 'blah', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]
person dansalmo    schedule 05.04.2013

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

>>> 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]
person Arindam Roychowdhury    schedule 22.03.2012

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

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

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

s[start:end:step]

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

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

Еще один важный момент: все _8 _, _ 9_, step можно опустить! И если они не указаны, будет использовано их значение по умолчанию: _11 _, _ 12 _, _ 13_ соответственно.

Итак, возможные варианты:

# 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

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

Будьте удивлены: slice не вызывает 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
person cizixs    schedule 09.01.2017

В предыдущих ответах не обсуждается нарезка многомерного массива, которая возможна с использованием известного пакета NumPy:

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

# Here, a is a NumPy array

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

«:2» перед запятой работает с первым измерением, а «0:3:2» после запятой работает со вторым измерением.

person Statham    schedule 01.03.2017
comment
Просто дружеское напоминание, что вы не можете сделать это на Python list, а только на array в Numpy - person Mars Lee; 27.07.2019

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

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

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

person Raman    schedule 23.08.2019

#!/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.

person mahmoh    schedule 18.10.2014

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

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

azString = "abcdefghijklmnopqrstuvwxyz"

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

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

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

a b [ c d e f g h ] i j

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

person asiby    schedule 12.12.2017

Мой мозг, кажется, счастлив принять, что 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.

person Robert    schedule 26.05.2016

В 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 может сильно запутать. Более того, чтобы быть 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]
person lmiguelvargasf    schedule 04.09.2017

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

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

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

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

person Roshan Bagdiya    schedule 06.10.2017

Я хочу добавить один пример 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'].

person Jeyekomon    schedule 04.04.2018

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

 +---+---+---+---+---+
 | 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
person Prince Dhadwal    schedule 28.07.2017

Если вы считаете, что отрицательные индексы при нарезке сбивают с толку, вот очень простой способ подумать об этом: просто замените отрицательный индекс на 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)]
person Shital Shah    schedule 19.12.2017

Я не думаю, что диаграмма учебника по 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  
person aguadopd    schedule 27.05.2019
comment
Используется сегодня 2021.07.19 лично мной, qué capo aguadopd del pasado - person aguadopd; 20.07.2021

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

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

Создайте два списка для разрезания. Первый - это числовой список от 1 до 9 (Список A). Второй - это тоже числовой список от 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 и step по умолчанию равны none - единственный обязательный аргумент - stop. Вы заметили, что это похоже на то, как диапазон использовался для определения списков A и B? Это связано с тем, что объект среза представляет набор индексов, заданных диапазоном (начало, остановка, шаг). Документация Python 3.4.

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

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

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

A[:]

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

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

person Babu Chandermani    schedule 23.07.2018

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

Я принял предложение Аарона Холла, прочитал соответствующие части исходного кода CPython и написал код Python, который выполняет нарезку аналогично тому, как это делается в CPython. Я протестировал свой код на Python 3 на миллионах случайных тестов в целочисленных списках.

Вы можете найти ссылки в моем коде на соответствующие функции в CPython.

# Return the result of slicing list x
# See the part of list_subscript() in listobject.c that pertains
# to when the indexing item is a PySliceObject
def slicer(x, start=None, stop=None, step=None):
    # Handle slicing index values of None, and a step value of 0.
    # See PySlice_Unpack() in sliceobject.c, which
    # extracts start, stop, step from a PySliceObject.
    maxint = 10000000       # A hack to simulate PY_SSIZE_T_MAX
    if step == None:
        step = 1
    elif step == 0:
        raise ValueError('slice step cannot be zero')

    if start == None:
        start = maxint if step < 0 else 0
    if stop == None:
        stop = -maxint if step < 0 else maxint

    # Handle negative slice indexes and bad slice indexes.
    # Compute number of elements in the slice as slice_length.
    # See PySlice_AdjustIndices() in sliceobject.c
    length = len(x)
    slice_length = 0

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

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

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

    # Cases of step = 1 and step != 1 are treated separately
    if slice_length <= 0:
        return []
    elif step == 1:
        # See list_slice() in listobject.c
        result = []
        for i in range(stop - start):
            result.append(x[i+start])
        return result
    else:
        result = []
        cur = start
        for i in range(slice_length):
            result.append(x[cur])
            cur += step
        return result
person grbruns    schedule 14.06.2019
comment
Я прочитал все соответствующие документы и обнаружил, что описания этого синтаксиса нет. Я усомнился в своих способностях и почувствовал облегчение, увидев этот ответ. Может, его и не было. - person Andy; 27.03.2021

Правила нарезки следующие:

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

person Anshika Singh    schedule 23.07.2020

Легко понять, можно ли связать срез с range, который дает индексы. Мы можем разделить нарезки на следующие две категории:


1. Ни одного шага или шага> 0. Например, [i:j] или [i:j:k] (k> 0)

Предположим, что последовательность равна s=[1,2,3,4,5].

  • если 0<i<len(s) и 0<j<len(s), то [i:j:k] -> range(i,j,k)

Например, [0:3:2] -> range(0,3,2) -> 0, 2

  • если i>len(s) или j>len(s), то i=len(s) или j=len(s)

Например, [0:100:2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4

  • если i<0 или j<0, то i=max(0,len(s)+i) или j=max(0,len(s)+j)

Например, [0:-3:2] -> range(0,len(s)-3,2) -> range(0,2,2) -> 0

Другой пример: [0:-1:2] -> range(0,len(s)-1,2) -> range(0,4,2) -> 0, 2

  • если i не указан, то i=0

Например, [:4:2] -> range(0,4,2) -> range(0,4,2) -> 0, 2

  • если j не указан, то j=len(s)

Например, [0::2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4


2. Шаг ‹0. Например, [i:j:k] (k‹ 0)

Предположим, что последовательность равна s=[1,2,3,4,5].

  • если 0<i<len(s) и 0<j<len(s), то [i:j:k] -> range(i,j,k)

Например, [5:0:-2] -> range(5,0,-2) -> 5, 3, 1

  • если i>len(s) или j>len(s), то i=len(s)-1 или j=len(s)-1

Например, [100:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • если i<0 или j<0, то i=max(-1,len(s)+i) или j=max(-1,len(s)+j)

Например, [-2:-10:-2] -> range(len(s)-2,-1,-2) -> range(3,-1,-2) -> 3, 1

  • если i не указан, то i=len(s)-1

Например, [:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • если j не указан, то j=-1

Например, [2::-2] -> range(2,-1,-2) -> 2, 0

Другой пример: [::-1] -> range(len(s)-1,-1,-1) -> range(4,-1,-1) -> 4, 3, 2, 1, 0


В итоге

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

person Banghua Zhao    schedule 28.12.2018

person    schedule
comment
Отличное объяснение. Но логика нарезки очень не интуитивно понятна. - person Moss; 19.08.2020