Files

295 lines
5.5 KiB
Markdown

---
sources: [summaries/01_Iteration_protocol.md, summaries/04_Sequences.md]
brief: Python 切片是一种用半开区间从序列中提取、替换或删除子序列的语法。
---
# Python 切片
Python 切片是一种从Python序列中选取子序列的语法,常用于字符串、列表、元组等有序数据结构。它在 [[summaries/04_Sequences]] 中作为序列操作的核心内容之一出现。
## 基本语法
切片的基本形式是:
```python
s[start:end]
```
其中:
- `s` 是一个序列,例如字符串、列表或元组。
- `start` 是切片起始索引。
- `end` 是切片结束索引。
- 结果包含 `start` 对应的元素,但不包含 `end` 对应的元素。
例如:
```python
a = [0, 1, 2, 3, 4, 5, 6, 7, 8]
a[2:5] # [2, 3, 4]
```
这里 `a[2:5]` 取出索引 `2`、`3`、`4` 的元素,但不包括索引 `5` 的元素。
## 半开区间规则
Python 切片遵循半开区间规则:
```text
[start, end)
```
也就是说:
- 包含起点 `start`。
- 不包含终点 `end`。
这与 `range()` 的行为一致:
```python
range(2, 5) # 2, 3, 4
```
这种设计使得切片长度容易计算:
```python
len(s[start:end]) == end - start
```
前提是索引在正常范围内。
相关概念可参见 range函数。
## 省略 start 或 end
切片中的 `start` 和 `end` 都可以省略。
### 省略 start
如果省略 `start`,默认从序列开头开始:
```python
a[:3] # [0, 1, 2]
```
等价于:
```python
a[0:3]
```
### 省略 end
如果省略 `end`,默认一直取到序列结尾:
```python
a[-5:] # [4, 5, 6, 7, 8]
```
### 同时省略 start 和 end
如果两者都省略,则得到整个序列的浅拷贝:
```python
a[:] # [0, 1, 2, 3, 4, 5, 6, 7, 8]
```
对于列表来说,这常用于复制列表。
## 负索引与切片
Python 序列支持负索引:
- `-1` 表示最后一个元素。
- `-2` 表示倒数第二个元素。
- 依此类推。
负索引也可以用于切片:
```python
a = [0, 1, 2, 3, 4, 5, 6, 7, 8]
a[-5:] # [4, 5, 6, 7, 8]
```
这表示从倒数第 5 个元素开始,一直取到结尾。
## 切片适用于多种序列
切片是序列类型的通用操作,常见适用对象包括:
- 字符串:
```python
s = 'Hello'
s[1:4] # 'ell'
```
- 列表:
```python
a = [0, 1, 2, 3]
a[1:3] # [1, 2]
```
- 元组:
```python
t = ('GOOG', 100, 490.1)
t[:2] # ('GOOG', 100)
```
切片返回的结果通常与原序列类型一致:
- 字符串切片返回字符串。
- 列表切片返回列表。
- 元组切片返回元组。
## 列表的切片赋值
在可变序列列表中,切片不仅可以读取,还可以重新赋值。
```python
a = [0, 1, 2, 3, 4, 5, 6, 7, 8]
a[2:4] = [10, 11, 12]
```
结果是:
```python
[0, 1, 10, 11, 12, 4, 5, 6, 7, 8]
```
这里原来的 `a[2:4]` 是:
```python
[2, 3]
```
它被替换为:
```python
[10, 11, 12]
```
注意:替换片段不需要与原片段长度相同。因此,切片赋值可以改变列表长度。
这体现了列表作为可变序列的特性。相比之下,字符串和元组不可变,不能通过切片赋值修改。
相关概念:Python序列。
## 切片删除
列表中的切片也可以被删除:
```python
a = [0, 1, 2, 3, 4, 5, 6, 7, 8]
del a[2:4]
```
结果是:
```python
[0, 1, 4, 5, 6, 7, 8]
```
这里删除了索引 `2` 和 `3` 的元素,也就是原来的 `2` 和 `3`。
## 与 range() 的一致性
切片和 `range()` 都采用“不包含结束值”的规则。
例如:
```python
a[2:5] # 索引 2, 3, 4
range(2, 5) # 数字 2, 3, 4
```
这种一致性降低了理解成本,也让序列处理、循环计数和索引计算更加统一。
参见 range函数 与 [[summaries/04_Sequences]]。
## 常见使用场景
### 提取前几个元素
```python
a[:3]
```
### 提取后几个元素
```python
a[-5:]
```
### 去掉开头或结尾部分
```python
a[1:] # 去掉第一个元素
a[:-1] # 去掉最后一个元素
```
### 复制列表
```python
b = a[:]
```
### 替换列表中间一段
```python
a[2:4] = [10, 11, 12]
```
### 删除列表中间一段
```python
del a[2:4]
```
## 易错点
### 1. end 不包含在结果中
很多初学者会误以为 `s[2:5]` 包含索引 `5`。实际上它只包含 `2`、`3`、`4`。
### 2. 切片索引必须是整数
`start` 和 `end` 必须是整数索引,不能使用浮点数或其他不合适的类型。
### 3. 只有可变序列支持切片赋值
列表支持:
```python
a[1:3] = [7, 8]
```
但字符串和元组不支持类似操作,因为它们是不可变对象。
### 4. 切片赋值可以改变列表长度
如下代码是合法的:
```python
a[2:4] = [10, 11, 12, 13]
```
替换后的元素数量可以多于或少于原片段。
## 与其他概念的关系
- Python序列:切片是序列类型的基本操作之一。
- range函数:切片和 `range()` 都采用半开区间规则。
- Python解包:切片常用于先取得子序列,再进一步解包或处理。
- enumerate函数:当需要带索引遍历序列时,`enumerate()` 通常比手动切片或索引循环更清晰。
- [[summaries/04_Sequences]]:本文档系统介绍了序列、切片、循环、`enumerate()` 和 `zip()` 等基础工具。
## 核心总结
Python 切片提供了一种简洁、统一的方式来处理序列的一部分。它基于半开区间 `[start, end)`,支持省略边界、负索引,并在列表中进一步支持切片赋值和删除。掌握切片是理解 Python 序列处理风格的重要基础。
See also: [[summaries/01_Iteration_protocol]]