Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。
另请参见:为什么切片和范围上限是互斥的?
Python的切片表示法是如何工作的?也就是说:当我编写[x:y:z]、a[:]、a]::2]等代码时,我如何理解哪些元素最终会出现在切片中?请在适当的地方附上参考资料。
另请参见:为什么切片和范围上限是互斥的?
当前回答
Python教程对此进行了讨论(向下滚动一点,直到您了解到关于切片的部分)。
ASCII艺术图也有助于记住切片的工作方式:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
记住切片工作方式的一种方法是将索引视为字符之间的指针,第一个字符的左边缘编号为0。然后,n个字符串的最后一个字符的右边缘具有索引n。
其他回答
我不认为Python教程图(在各种其他答案中引用)是好的,因为这个建议适用于积极的步幅,但不适用于消极的步幅。
这是一个图表:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
从图中,我希望[-4,-6,-1]是yP,但它是ty。
>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'
始终有效的方法是在字符或槽中思考,并将索引用作半开区间——如果是正步幅,则右开,如果是负步幅,那么左开。
这样,我可以将[-4:-6:-1]看作是区间术语中的(-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
上面的答案不讨论切片分配。为了理解切片分配,可以在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]
这也可以澄清切片和索引之间的区别。
前面的答案没有讨论使用著名的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”作用于第二维度。
当我第一次看到切片语法时,有一些事情不是很明显:
>>> 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]
前面的大多数答案都解决了有关切片表示法的问题。
用于切片的扩展索引语法是aList[start:stop:step],基本示例如下:
:
更多切片示例:15个扩展切片