Python切片 1012:从入门到精通
Python 切片是一种非常强大且优雅的特性,它允许你轻松地获取序列(如列表、元组、字符串)的一部分,而无需编写复杂的循环,掌握切片是 Python 编程的必备技能。

第一部分:101 切片基础 - 搞懂 [:]
切片的基本语法非常简单,核心是方括号 [] 和冒号 。
sequence[start:stop:step]
让我们来分解这三个参数:
sequence: 你想要切片的对象,my_list = [0, 1, 2, 3, 4, 5]。start: 起始索引,切片将从这个索引开始,包含这个索引本身,如果省略,默认为0。stop: 结束索引,切片将在这个索引之前结束,不包含这个索引本身,如果省略,默认为序列的长度。step: 步长,表示每次取元素时要“跳过”几个,如果省略,默认为1。
最简单的切片:复制整个序列
当你不提供任何参数时,[:] 会创建一个原序列的浅拷贝。

my_list = [0, 1, 2, 3, 4, 5] new_list = my_list[:] print(new_list) # 输出: [0, 1, 2, 3, 4, 5] print(new_list is my_list) # 输出: False,证明是两个不同的对象
只提供 stop:从开头到指定位置
my_list = [0, 1, 2, 3, 4, 5] # 获取索引 0 到 3 (不包含 3) 的元素 slice_result = my_list[:3] print(slice_result) # 输出: [0, 1, 2]
只提供 start:从指定位置到结尾
my_list = [0, 1, 2, 3, 4, 5] # 获取索引 2 到结尾的元素 slice_result = my_list[2:] print(slice_result) # 输出: [2, 3, 4, 5]
同时提供 start 和 stop:从指定位置到指定位置
my_list = [0, 1, 2, 3, 4, 5] # 获取索引 1 到 4 (不包含 4) 的元素 slice_result = my_list[1:4] print(slice_result) # 输出: [1, 2, 3]
提供所有三个参数:加入步长
my_list = [0, 1, 2, 3, 4, 5] # 从索引 1 开始,到索引 5 结束,每隔 2 个取一个 slice_result = my_list[1:5:2] print(slice_result) # 输出: [1, 3] (取索引 1,1+2=3,3+2=5,但5不包含) # 获取所有元素,但每隔一个取一个 (俗称“隔一个取一个”) slice_result = my_list[::2] print(slice_result) # 输出: [0, 2, 4]
第二部分:102 进阶技巧 - 负索引和省略参数
现在我们来看看让切片变得更灵活的两种技巧。
负索引
Python 支持负索引,它从序列的末尾开始计数。-1 是最后一个元素,-2 是倒数第二个,以此类推。
my_list = [0, 1, 2, 3, 4, 5] # 获取倒数第三个元素到结尾 slice_result = my_list[-3:] print(slice_result) # 输出: [3, 4, 5] # 获取从开头到倒数第三个元素 (不包含) slice_result = my_list[:-3] print(slice_result) # 输出: [0, 1, 2] # 获取倒数第四个到倒数第二个元素 slice_result = my_list[-4:-1] print(slice_result) # 输出: [2, 3, 4]
省略 start 或 stop 与负步长结合
当 step 为负数时,切片会从后往前取,这时,start 和 stop 的默认值会发生变化:
start的默认值是序列的最后一个元素(索引-1)。stop的默认值是序列的开头(索引-len(sequence)-1,即最前面一个元素的前面)。
技巧:使用 [::-1] 来反转序列

这是 Python 中最酷、最常用的切片技巧之一!
my_list = [0, 1, 2, 3, 4, 5] # 反转列表 reversed_list = my_list[::-1] print(reversed_list) # 输出: [5, 4, 3, 2, 1, 0] my_string = "Python" reversed_string = my_string[::-1] print(reversed_string) # 输出: "nohtyP"
其他负步长例子:
my_list = [0, 1, 2, 3, 4, 5] # 从倒数第二个元素开始,到开头结束,步长为 -1 (相当于 my_list[-1::-1]) slice_result = my_list[-2::-1] print(slice_result) # 输出: [4, 3, 2, 1, 0, 5] (从4开始,一直往前取) # 从倒数第二个元素开始,取到倒数第五个元素 (不包含),步长为 -1 slice_result = my_list[-2:-5:-1] print(slice_result) # 输出: [4, 3, 2]
第三部分:重要注意事项和边界情况
索引越界怎么办?
Python 切片非常“宽容”,即使你提供的 start 或 stop 超出了序列的范围,它也不会报错,而是会自动调整到有效的边界。
my_list = [0, 1, 2, 3, 4, 5] # start 超出范围 print(my_list[10:]) # 输出: [] (从第10个开始,但没有,所以返回空列表) # stop 超出范围 print(my_list[:10]) # 输出: [0, 1, 2, 3, 4, 5] (取到第10个,但列表只有6个,所以取全部) # start > stop 且 step 为正 print(my_list[5:2]) # 输出: [] (从5开始,要到2结束,但步长是正的,所以无法前进,返回空)
切片是“浅拷贝”
切片操作会创建一个包含原序列部分元素的新序列,对于列表等可变对象,新列表中的元素是对原列表中元素的引用。
这意味着,如果元素是不可变的(如数字、字符串、元组),修改新列表不会影响原列表,但如果元素是可变的(如另一个列表),情况就不同了。
# 情况一:元素是不可变的
list_a = [1, 2, 3]
list_b = list_a[:]
list_b[0] = 99
print(f"list_a: {list_a}") # 输出: list_a: [1, 2, 3]
print(f"list_b: {list_b}") # 输出: list_b: [99, 2, 3]
# 情况二:元素是可变的(嵌套列表)
list_c = [[1, 2], [3, 4]]
list_d = list_c[:]
# 修改 list_d 中的第一个元素 (这是一个列表)
list_d[0].append(99)
print(f"list_c: {list_c}") # 输出: list_c: [[1, 2, 99], [3, 4]]
print(f"list_d: {list_d}") # 输出: list_d: [[1, 2, 99], [3, 4]]
# 因为 list_d[0] 和 list_c[0] 指向的是同一个列表对象,所以修改会相互影响。
