Python中的切片表示法

Python/Java学习交流群:369606713


Python中的切片表示法


语法

a[start:end] # 项目从 start 到 end-1
a[start:]    # 项目从 start 到最后
a[:end]      # 项目从开始到end-1
a[:]         # 整个
a[start:end:step] # 从start到end,步长是step

注意: 另一个特征是start或者end可能是负数,这意味着它从数组的末尾而不是从开头开始计数。所以,

a[-1]    # 最后一个
a[-2:]   # 最后两个
a[:-2]   # 除最后两个之外的

同样,step可能是负数:

a[::-1]    # 所有项目的逆序
a[1::-1]   # 前两项逆序
a[:-3:-1]  # 最后两项逆序
a[-3::-1]  # 除了最后两项,其他逆序

图示记忆

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

实例

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

其他助记法

+---+---+---+---+---+---+
                | 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']
# 对这两组数字的解释
# 索引得到项目,不是列表
>>> p[0]
 'P'
>>> p[5]
 'n'
# 切片得到列表
>>> p[0:1]
 ['P']
>>> p[0:2]
 ['P','y']

对于从零到n的切片,一种启发式方法是:“零是开始,从开始处开始并在列表中取n个项目”。

>>> p[5] # 六项中的最后一项,从零开始索引
 'n'
>>> p[0:5] # 不包括最后一项!
 ['P','y','t','h','o']
>>> p[0:6] # not p[0:5]!!!
 ['P','y','t','h','o','n']

另一种启发式方法是,“对于任何切片,将起点替换为零,应用先前的启发式来获取列表的末尾,然后将第一个数字重新计算,以便从一开始就删除项目”

>>> p[0:4] # 从头开始计算4项
 ['P','y','t','h']
>>> p[1:4] # 从前一个取
 ['y','t','h']
>>> p[2:4] # 从前两个取
 ['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'] # 再来看看
>>> 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'] # 分配的列表与切片的长度相同
>>> p
 ['P','y','x','y','o','n'] # 结果是相同的长度
>>> p = ['P','y','t','h','o','n']
>>> p[3:4] = ['x','y'] # 分配的列表比切片长
>>> p
 ['P','y','t','x','y','o','n'] # 结果更长
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
 ['P','y','t','h','x','y','o','n'] # 结果更长

请注意,由于我们没有更改slice(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=[0,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]

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