Python切片操作详解:原理、赋值与陷阱

键盘旁的猫
键盘旁的猫
发布时间:2026-10-16 | 5人浏览过
原创

本文深入解析Python中字符串、列表和元组的切片操作。详细讲解切片语法[start:stop:step]、底层slice对象机制及indices方法计算逻辑。重点剖析切片赋值的迭代约束,并揭示二维列表初始化中引用共享导致的修改陷阱,提供正确的独立初始化方案,帮助开发者避免常见错误。

1. 前言

初学Python时,我们了解到字符串(String)、列表(list)和元组(tuple)等序列数据类型均支持切片功能。

# slice operation
TUPLE = (1,2,3,4)
LIST = [1,2,3,4]
STRING = "1234"

print("TUPLE[1:3]:",TUPLE[1:3])
print("LIST[1:3]:",LIST[1:3])
print("STRING[1:3]:",STRING[1:3])

# output
TUPLE[1:3]: (2, 3)
LIST[1:3]: [2, 3]
STRING[1:3]: 23

借助示例,我们可以迅速通过“区间”方式提取目标数据。值得注意的是,切片结果始终不包含末尾元素。接下来,我们将对这一常用操作进行系统化梳理。

2. 什么是切片

2.1 切片概述

Python序列数据的索引从左至右由0开始递增;若从右向左索引,则从-1开始递减。

在Python中访问子序列或字符串时,使用方括号[]指定截取范围。例如,若要从列表中获取元素2和3,切片表达式应写为LIST[1:3]。

2.2 忽略最后一位元素

Python切片默认不包含结束索引对应的元素,这种设计与C语言等语言中索引从0开始的惯例保持一致。

这种忽略末尾元素的设计具有以下优势:

当切片仅指定结束索引时,可直接看出截取子序列的长度。例如LIST[:2]包含两个元素。

正如Edsger W. Dijkstra所指出的,索引从0开始优于从1开始,因为元素的序数(下标)等于其之前的元素数量。因此,切片长度可直接通过(stop-start)计算得出。

此外,对于任意索引位置x,序列可被切割为两个不重叠的子序列LIST[:x]和LIST[x:]。

 >>> LIST = [1,2,3,4] 
>>> LIST[:2] # 直接可以知道截取子序列为2
[1, 2]
>>> LIST[2:] # 将LIST在索引位置2处切片
[3, 4]
>>> 

3. 切片原理

切片操作通过方括号[]执行,格式为[start:stop:step]。系统从start到stop区间内,按步长step提取元素,step可为负数。

>>> LIST[1:4:2] 
[2, 4]
>>> LIST[-1:-4:-1] 
[4, 3, 2]
>>> LIST[::-1] 
[4, 3, 2, 1]
>>> LIST[::-2] 
[4, 2]
>>>

方括号内的start:stop:step表达式会返回一个切片对象:slice(start,stop,step)。

当对序列执行seq[start:stop:step]时,Python会调用seq.getitem(slice(start,stop,step))方法,以元组形式接收方括号索引。

查看Python内置slice()方法的属性,包含start、stop和step三个数据属性,以及indices方法。

>>> slice  
<class 'slice'>
>>> dir(slice) 
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__',
 '__hash__', '__init__', '__init_subclass__', '__le__', 
 '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
 '__repr__', '__setattr__', '__sizeof__', '__str__', 
'__subclasshook__', 'indices', 'start', 'step', 'stop']
>>>

序列调用slice方法后,会先执行Seq.indices(len)方法,计算出从start到stop、步长为step的实际范围。若超出边界,则自动截断处理。

>>> slice(None,5,1).indices(2) #1
(0, 2, 1)
>>> slice(-3,None,None).indices(2) #2
(0, 2, 1)
>>>

#1 seq[:5:1] 等价于 seq[0:2:1]

#2 seq[-3:] 等价于 seq[0:2:1]

切片还支持使用逗号分隔多个索引,例如第三方库Numpy便利用此特性实现多维数组操作。

4. 切片赋值

对序列进行切片操作得到切片对象后,可进行赋值,但需满足以下条件:

作为切片对象的等号右侧,必须是一个可迭代对象。

即使切片仅包含一个值,也必须转换为可迭代序列。

否则,系统将抛出TypeError异常。

>>> LIST = [1,2,3,4,5]
>>> LIST[1:4] = 23
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable
>>>

5. 切片计算

在Python中,切片对象支持“+”或“*”运算,用于拼接组合成新的切片对象。

使用“+”连接两个同类型序列,拼接后原序列不变,Python内部会创建新序列。

>>> LIST = [1,2,3,4]
>>> LIST2 = [5,6,7]
>>> LIST + LIST2
[1, 2, 3, 4, 5, 6, 7]
>>> s1 = "Jue"    
>>> s2 = "Jin" 
>>> s1 + s2
'JueJin'

通过“Seq*n”,可将原数据类型复制n份并拼接,形成新序列。

>>> LIST = [1,2,3,4]
>>> LIST * 3
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
>>> s1 = "Jue"       
>>> s1 * 3
'JueJueJue'

上述案例均针对不可变数据类型。若元素为可变数据类型,复制行为会有所不同。

例如创建长度为3的二维列表,快捷写法如下:

>>> LIST = [["_"]]*3 
>>> LIST
[['_'], ['_'], ['_']]

但当对坐标0,0进行赋值时,发现三个元素均发生变化。

>>> LIST[0][0] = 1
>>> LIST
[[1], [1], [1]]

这与预期不符,我们需要每个元素相互独立,因此写法需与上述有所区别。

>>> LIST = [["_"] for i in range(3)] 
>>> LIST
[['_'], ['_'], ['_']]
>>> LIST[0][0] = 1
>>> LIST
[[1], ['_'], ['_']]
>>>

两种写法差异巨大的原因在于:第一种写法初始化时,所有元素引用指向同一个列表对象。对其中一个元素赋值时,其他元素随之变化。

6. 总结

本期深入学习了Python序列和字符串的切片操作。其原理在于Python内部通过__getitem__()方法调用slice对象,进而由slice对象通过indices(len)方法计算切片长度。即使遇到缺失索引、负数索引或超出目标序列长度的切片,Python也能优雅处理。

到此这篇关于Python中切片操作的示例详解的文章就介绍到这了,更多相关Python切片操作内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表