Python 切片的核心概念
Python 切片的核心概念
切片(Slicing)是从一个序列(如字符串、列表、元组)中“切”出一个子序列。它的通用语法是 [start:stop:step]
。
start
:切片的起始索引(包含该索引)。如果省略,默认从序列的开头(索引 0)开始。stop
:切片的结束索引(不包含该索引)。如果省略,默认到序列的末尾。step
:步长,即每隔多少个元素取一个。如果省略,默认为 1。
而[:]
是最简单的一种切片形式,它省略了所有参数,因此使用所有默认值:[0:len(sequence):1]
。
[:]
的真正威力:创建浅拷贝
[:]
最重要、也最容易被忽视的作用是创建一个全新的、独立的列表副本,而不是仅仅创建一个指向原列表的引用。
这在处理复杂数据时至关重要。比如,你在编译器里解析出一个语法树列表,如果需要对这个列表进行某种转换或分析,你肯定不希望这个过程意外地修改了原始的语法树。这时 [:]
就派上用场了。
切片操作详解与示例表格
下面这个表格详细列出了各种切片组合的效果,我们用一个简单的列表 data = [10, 20, 30, 40, 50, 60]
来举例。
切片表达式 | 等价形式 | 结果 | 解释说明 |
---|---|---|---|
data[:] | data[0:6:1] | [10, 20, 30, 40, 50, 60] | 全选。从开头到结尾,步长为1。核心作用:创建一个浅拷贝。 |
data[2:] | data[2:6:1] | [30, 40, 50, 60] | 从索引 2 开始,一直切到末尾。 |
data[:4] | data[0:4:1] | [10, 20, 30, 40] | 从开头开始,切到索引 4(不包含4)。 |
data[2:5] | data[2:5:1] | [30, 40, 50] | 从索引 2 开始,切到索引 5(不包含5)。 |
data[::2] | data[0:6:2] | [10, 30, 50] | 从头到尾,每隔 2 个元素取一个。 |
data[1::2] | data[1:6:2] | [20, 40, 60] | 从索引 1 开始,每隔 2 个元素取一个。 |
data[::-1] | data[5:-1:-1] | [60, 50, 40, 30, 20, 10] | 反转序列。步长为 -1,从末尾到开头。 |
data[5:1:-1] | (无) | [60, 50, 40, 30] | 从索引 5 开始,反向切片到索引 1(不包含1)。 |
data[-3:] | data[3:6:1] | [40, 50, 60] | 负索引表示从末尾开始。-1是最后一个元素,-3是倒数第三个。 |
data[:-2] | data[0:4:1] | [10, 20, 30, 40] | 切到倒数第二个元素(不包含它)。 |
结合你的背景举个例子
想象一下,你的简易编译器在词法分析阶段,把一行代码 result = a + b * 10
分割成了一个 token 列表:
original_tokens = ['IDENTIFIER(result)', 'EQUALS', 'IDENTIFIER(a)', 'PLUS', 'IDENTIFIER(b)', 'MULTIPLY', 'NUMBER(10)']
现在,你需要对这个表达式进行语法分析,但你不想破坏 original_tokens
,因为它可能还需要用于后续的错误报告或代码生成。
错误的做法(直接赋值):
# 只是复制了一个引用,它们指向同一个列表对象
tokens_for_parsing = original_tokens
# 假设在解析过程中,你发现需要替换一个 token
tokens_for_parsing[3] = 'OPERATOR(PLUS)'
# 糟糕!原始列表也被修改了!
print(f"原始 Token 列表: {original_tokens}")
# 输出: ['IDENTIFIER(result)', 'EQUALS', 'IDENTIFIER(a)', 'OPERATOR(PLUS)', 'IDENTIFIER(b)', 'MULTIPLY', 'NUMBER(10)']
正确的做法(使用 [:]
):
# 使用 [:] 创建一个独立的副本
tokens_for_parsing = original_tokens[:]
# 在副本上进行修改
tokens_for_parsing[3] = 'OPERATOR(PLUS)'
# 现在原始列表安然无恙
print(f"原始 Token 列表: {original_tokens}")
# 输出: ['IDENTIFIER(result)', 'EQUALS', 'IDENTIFIER(a)', 'PLUS', 'IDENTIFIER(b)', 'MULTIPLY', 'NUMBER(10)']
print(f"用于解析的副本: {tokens_for_parsing}")
# 输出: ['IDENTIFIER(result)', 'EQUALS', 'IDENTIFIER(a)', 'OPERATOR(PLUS)', 'IDENTIFIER(b)', 'MULTIPLY', 'NUMBER(10)']