了解切片表示法

问题描述 投票:2803回答:31

我需要在Python的切片表示法上有一个很好的解释(引用是一个加号)。

对我来说,这种符号需要一点点提升。

它看起来非常强大,但我还没有完全了解它。

python list slice iterable
31个回答
3919
投票

它非常简单:

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值表示不在所选切片中的第一个值。因此,stopstart之间的差异是所选元素的数量(如果step为1,则为默认值)。

另一个特征是startstop可能是一个负数,这意味着它从数组的末尾而不是从开头算起。所以:

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只包含一个元素,则会得到一个空列表而不是错误。有时您会更喜欢错误,因此您必须意识到这可能会发生。

Relation to slice() object

切片运算符[]实际上在上面的代码中使用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()对象的显式使用简化了切片的编程生成。


46
投票

我发现它更容易记住它是如何工作的,然后我可以找出任何特定的开始/停止/步骤组合。

首先理解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]就是整个字符串。


37
投票
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


36
投票

我自己使用“元素之间的索引点”方法来思考它,但是一种描述它的方法有时会帮助其他人得到它是这样的:

mylist[X:Y]

X是您想要的第一个元素的索引。 Y是您不想要的第一个元素的索引。


35
投票

Python切片表示法:

a[start:end:step]
  • 对于startend,负值被解释为相对于序列的末尾。
  • end的正指数表示在包括最后一个元素之后的位置。
  • 空白值默认如下:[+0:-0:1]
  • 使用负步骤反转了startend的解释

符号扩展到(numpy)矩阵和多维数组。例如,要切片整列,您可以使用:

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

切片保存数组元素的引用,而不是副本。如果要单独复制数组,可以使用deepcopy()


32
投票

您还可以使用切片分配从列表中删除一个或多个元素:

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

32
投票

这就是我教给新手的切片的方法:

了解索引和切片之间的区别:

Wiki Python有这个令人惊叹的图片,清楚地区分索引和切片。

它是一个包含6个元素的列表。要更好地理解切片,请将该列表视为一组放在一起的六个框。每个方框都有一个字母。

索引就像处理框的内容一样。您可以查看任何框的内容。但是你不能一次检查多个盒子的内容。您甚至可以替换该框的内容。但你不能将2个球放在一个盒子里或一次更换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

切片就像处理盒子一样。您可以先取出盒子并将其放在另一张桌子上。拾取盒子你需要知道的是盒子开始和结束的位置。

您甚至可以在1到4之间拾取前3个盒子或最后2个盒子或所有盒子。因此,如果您知道开始和结束,您可以选择任何一组盒子。这个位置称为开始和停止位置。

有趣的是,您可以一次更换多个盒子。您也可以在任何地方放置多个盒子。

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中写的


31
投票

这只是一些额外的信息......请考虑下面的列表

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

27
投票

作为一般规则,编写具有大量硬编码索引值的代码会导致可读性和维护混乱。例如,如果你在一年之后回到代码中,你会看到它并想知道你在编写代码时的想法。显示的解决方案只是一种更清楚地说明代码实际执行情况的方法。通常,内置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.start,s.stop和s.step属性来获取有关切片实例的更多信息。例如:

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

26
投票

1. Slice Notation

为简单起见,请记住切片只有一种形式:

s[start:end:step]

以下是它的工作原理:

  • s:可以切片的物体
  • start:开始迭代的第一个索引
  • end:最后一个索引,请注意end索引不会包含在结果切片中
  • step:每个step指数挑选元素

另一件重要的事情:所有qazxsw poi,qazxsw poi,qazxsw poi都可以省略!如果省略它们,将使用它们的默认值:startendstep

所以可能的变化是:

0

注意:如果len(s)(仅考虑1),python将返回一个空切片# 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[:]

2. Pitfalls

上面的部分解释了切片如何工作的核心功能,它将在大多数情况下工作。然而,你应该注意可能存在的缺陷,这部分解释了它们。

负指数

困扰python学习者的第一件事就是索引可能是负面的!不要惊慌:负面指数意味着倒数。

例如:

start>=end

消极的一步

让事情更加混乱的是,step>0也可能是负面的!

否定步骤意味着向后迭代数组:从结束到开始,包括结束索引,并从结果中排除开始索引。

注意:当step为负数时,[]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

超出范围错误?

感到惊讶:当索引超出范围时,切片不会引发IndexError!

如果索引超出范围,python将根据情况尽力将索引设置为s[::-1]s[0]。例如:

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

3. Examples

让我们通过实例解释我们讨论的所有内容来完成这个答案:

0

20
投票

上面的答案没有讨论使用着名的NumPy包可能实现的多维数组切片:

切片也可以应用于多维数组。

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] ”在第一维上运行,而逗号之后的“# 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 ”在第二维上运行。


505
投票

Python tutorial谈论它(向下滚动一下,直到你得到关于切片的部分)。

ASCII艺术图也有助于记住切片的工作方式:

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

记住切片如何工作的一种方法是将索引视为指向字符之间,第一个字符的左边缘编号为0.然后,n个字符的字符串的最后一个字符的右边缘具有索引n。


14
投票
# 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

使用否定步骤时,请注意答案向右移动1。


14
投票

我的大脑似乎很高兴接受0:3:2包含#!/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] 元素。

在这些时刻,我依靠这个简单的定理:

lst[start:end]

这个漂亮的属性告诉我,start不包含end项,因为它在for any n, lst = lst[:n] + lst[n:]

请注意,这个定理适用于任何lst[start:end]。例如,您可以检查

end

返回lst[end:]


11
投票

在Python中,切片的最基本形式如下:

n

其中lst = range(10) lst[:-42] + lst[-42:] == lst 是一些集合,True是一个包容性指数,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提供了一个有用的技巧来反转Python中的集合:

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

但是,使用In [25]: l[::-1] Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 的负值可能会变得非常混乱。此外,为了成为Pythonic,你应该避免在一个切片中使用stepIn[28]: l[::-2] Out[28]: [9, 7, 5, 3, 1] step。如果需要这样做,请考虑在两个分配中执行此操作(一个用于切片,另一个用于步长)。

start

11
投票

关于Slice符号,上述大多数答案都清楚了。用于切片的扩展索引语法是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]


9
投票

以下是字符串索引的示例

aList[start:stop:step]

切片示例:[start:end:step]

enter image description here

以下是示例用法

15 Extended Slices

8
投票

在我看来,如果你按照以下方式查看它,你将更好地理解和记住Python字符串切片符号(继续阅读)。

让我们使用以下字符串...

 +---+---+---+---+---+
 | 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 创建任何子串。

来自其他编程语言,这就是常识被泄露的时候。什么是x和y?

在我寻求记忆技术时,我不得不坐下来运行几个场景,这将帮助我记住x和y是什么,并帮助我在第一次尝试时正确切割字符串。

我的结论是x和y应该被视为围绕我们想要额外的字符串的边界索引。因此,我们应该将表达式视为azString = "abcdefghijklmnopqrstuvwxyz" ,或者更加清晰,因为azString

这是一个示例可视化...

azString[x:y]

因此,如果要将index1和index2设置为围绕所需子字符串的值,则需要做的所有操作。例如,要获取子字符串“cdefgh”,您可以使用azString[index1, index2],因为“c”左侧的索引是2,而右侧大小“h”的索引是8。

请记住,我们正在设定界限。这些边界是你可以放置一些括号的位置,这些括号将围绕子串包裹......

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

这个技巧一直有效,很容易记忆。


7
投票

我想添加一个Hello world示例,它解释了初学者的切片基础知识。这对我帮助很大。

让我们有一个包含六个值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

现在,该列表中最简单的切片是其子列表。符号是azString[2:8],关键是这样读:

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


5
投票

如果你觉得切片中的负面指数令人困惑,可以用以下方法来思考:只需用2替换负指数。例如,用5替换-3。

说明内部切片的最佳方法是在实现此操作的代码中显示它:

['T', 'H', 'O']

4
投票

基本切片技术是定义起点,停止点和步长 - 也称为步幅。

首先,我们将创建一个值列表,以便在切片中使用。

创建两个要切片的列表,第一个是1到9的数字列表(列表A)。第二个也是数字列表,从0到9(列表B)

len - index

从A中索引数字3,从B中索引数字6。

len(list) - 3

基本切片

用于切片的扩展索引语法是aList [start:stop:step]。 start参数和step参数都默认为none - 唯一必需的参数是stop。您是否注意到这与使用范围定义列表A和B的方式类似?这是因为切片对象表示由范围(开始,停止,步骤)指定的索引集。 Python 3.4文档

如您所见,仅定义stop会返回一个元素。由于start默认为none,因此转换为仅检索一个元素。

需要注意的是,第一个元素是索引0,而不是索引1.这就是为什么我们在本练习中使用2个列表。列表A的元素根据序数位置编号(第一个元素是1,第二个元素是2等),而列表B的元素是用于索引它们的数字([0]表示第一个元素0,等等)。

使用扩展索引语法,我们检索一系列值。例如,使用冒号检索所有值。

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 for-loop with start, end and step
  return [list[i] for i in range(start, end, step)]

要检索元素的子集,需要定义起始位置和停止位置。

给定模式aList [start:stop],从List A中检索前两个元素


2
投票

如果我们可以将切片与A = list(range(1,10,1)) # start,stop,step B = list(range(9)) print("This is List A:",A) print("This is List B:",B) 相关联,这很容易理解,print(A[2]) print(B[6]) 给出了索引。我们可以将切片分为以下两类:


1.没有步骤或步骤> 0.例如,A[:] range(k> 0)

假设序列是[i:j]

  • 如果[i:j:k]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<0j<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


2.步骤<0。例如,j=len(s)(k <0)

假设序列是[0::2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4

  • 如果[i:j:k]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<0j<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


384
投票

列举语法允许的可能性:

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

1
投票

我不认为[::-1] -> range(len(s)-1,-1,-1) -> range(4,-1,-1) -> 4, 3, 2, 1, 0图(在其他答案中引用)是好的,因为这个建议适用于积极的步伐,但不是为了消极的步伐。

这是图:

enter image description here

从图中,我希望Python tutorial +---+---+---+---+---+---+ | 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]

283
投票

上面的答案不讨论切片分配。要理解切片分配,为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]

这也可以澄清切片和索引之间的区别。


234
投票

解释Python的切片表示法

简而言之,下标符号(:)中的冒号(subscriptable[subscriptarg])制作切片符号 - 其中包含可选参数startstopstep

sliceable[start:stop:step]

Python切片是一种有条不紊地访问部分数据的计算速度快的方法。在我看来,要成为一名中级Python程序员,它是必须熟悉的语言的一个方面。

重要定义

首先,让我们定义一些术语:

start:切片的起始索引,它将包括此索引处的元素,除非它与stop相同,默认为0,即第一个索引。如果它是负数,则意味着从最后开始n项目。

stop:切片的结束索引,它不包括此索引处的元素,默认为被切片序列的长度,即直到并包括结尾。

step:索引增加的数量,默认为1.如果是负数,则反向切换迭代。

索引如何工作

您可以制作任何正数或负数。正数的含义很简单,但对于负数,就像Python中的索引一样,从开始和结束的末尾向后计数,对于步骤,您只需递减索引。这个例子是from the documentation's tutorial,但我稍微修改了它以指示每个索引引用的序列中的哪个项:

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

切片如何工作

要使用带有支持它的序列的切片表示法,必须在序列后面的方括号中包含至少一个冒号(实际上是implement the __getitem__ method of the sequence, according to the Python data model。)

切片表示法的工作方式如下:

sequence[start:stop:step]

并且回想一下,启动,停止和步骤都有默认值,因此要访问默认值,只需省略参数即可。

从列表中获取最后九个元素的切片表示法(或任何其他支持它的序列,如字符串)将如下所示:

my_list[-9:]

当我看到这个时,我将括号中的部分读作“从结尾到结尾的第9个”。 (实际上,我在精神上将其缩写为“-9,on”)

说明:

完整的符号是

my_list[-9:None:None]

并替换默认值(实际上当step为负数时,stop的默认值为-len(my_list) - 1,所以None for stop实际上只是意味着它会转到最后一步):

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

冒号:告诉Python你给它一个切片而不是常规索引。这就是为什么在Python 2中制作浅表列表的惯用方法是

list_copy = sequence[:]

清除它们是:

del my_list[:]

(Python 3获得了list.copylist.clear方法。)

When step is negative, the defaults for start and stop change

默认情况下,当step参数为空(或None)时,它将被分配给+1

但是你可以传入一个负整数,并且列表(或大多数其他标准的可切片)将从末尾开始切片。

因此,负片会改变startstop的默认值!

Confirming this in the source

我想鼓励用户阅读源代码和文档。 source code for slice objects and this logic is found here。首先,我们确定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);
}

然后,我们可能需要应用startstop的默认值 - 当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);
}

Give your slices a descriptive name!

您可能会发现将切片与将其传递给list.__getitem__方法(that's what the square brackets do)分开是有用的。即使您不是新手,它也会使您的代码更具可读性,以便其他可能必须阅读您的代码的人可以更容易地理解您正在做的事情。

但是,您不能只将由冒号分隔的整数分配给变量。您需要使用切片对象:

last_nine_slice = slice(-9, None)

第二个参数None是必需的,因此第一个参数被解释为start参数otherwise it would be the stop argument

然后,您可以将切片对象传递给序列:

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

有趣的是,范围也需要切片:

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

Memory Considerations:

由于Python列表的切片在内存中创建了新对象,因此要注意的另一个重要功能是itertools.islice。通常,您需要迭代切片,而不是仅在内存中静态创建。 islice非常适合这种情况。需要注意的是,它不支持startstopstep的负面参数,因此如果这是一个问题,您可能需要提前计算索引或反转迭代。

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这样的高级对象,它可能会返回原始视图,而不是副本。


139
投票

当我第一次看到切片语法时,有些事情对我来说并不是很明显:

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

94
投票

在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结束(不包括bth索引处的元素)。使用上面的索引规则并记住您只能找到此范围内的元素:

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

92
投票

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)

59
投票

稍微使用它之后,我意识到最简单的描述是它与for循环中的参数完全相同...

(from:to:step)

其中任何一个都是可选的:

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

然后负索引只需要你将字符串的长度添加到负索引以理解它。

无论如何这对我有用......

© www.soinside.com 2019 - 2024. All rights reserved.