序列通用操作:索引与切片、拼接与重复、成员资格检查
序列这东西,说白了就是一组有序数据的集合。Python 里的字符串、列表、元组,都属于序列。它们虽然用途不同,但有一整套通用的操作——索引、切片、拼接、重复、成员检查。这些操作你天天都会用,但用对、用好,还是有不少门道的。
我记得刚入行那会儿,写爬虫解析 HTML,就因为索引搞错了一位,抓回来的数据全是乱的。排查了整整一下午。嗯,从那以后我对序列操作就格外小心了。
3.1 索引:从 0 开始,别搞错
序列里的每个元素都有个位置编号,叫索引。Python 的索引从 0 开始,不是 1。这一点,新手最容易栽跟头。
# 字符串索引
text = "Python"
print(text[0]) # 'P'
print(text[1]) # 'y'
print(text[5]) # 'n'
Python 还支持负数索引。从右往左数,-1 是最后一个元素。这个设计很巧妙,我特别喜欢用。
print(text[-1]) # 'n'
print(text[-2]) # 'o'
print(text[-6]) # 'P'
seq[-1],别用 seq[len(seq)-1]。又短又清晰,还不会算错。
索引越界会抛 IndexError。我曾经在生产环境里遇到过,因为列表长度动态变化,没做边界检查,直接崩了。所以,动态数据一定要先判断长度。
3.2 切片:取子序列的利器
切片语法是 seq[start:stop:step]。左闭右开——包含 start,不包含 stop。这个规则很多人记混。
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(nums[2:5]) # [2, 3, 4]
print(nums[:4]) # [0, 1, 2, 3]
print(nums[6:]) # [6, 7, 8, 9]
print(nums[:]) # 整个列表的副本
步长 step 默认是 1。设为负数可以反向切片。这个技巧在反转序列时特别好用。
print(nums[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print(nums[::2]) # [0, 2, 4, 6, 8]
print(nums[1::2]) # [1, 3, 5, 7, 9]
stop 超出序列长度,Python 也不会报错,只是返回能取到的部分。这既是优点也是隐患——你可能会以为数据够长,结果拿到的比预期少。
切片返回的是新对象。对于列表,是浅拷贝;对于字符串,是新的字符串。记住,修改切片不会影响原序列。
3.3 拼接与重复
拼接用 +,重复用 *。这两个操作符在序列上很直观。
# 拼接
a = [1, 2, 3]
b = [4, 5, 6]
print(a + b) # [1, 2, 3, 4, 5, 6]
# 重复
print(a * 3) # [1, 2, 3, 1, 2, 3, 1, 2, 3]
字符串也一样:
greeting = "Hi" + " " + "there"
print(greeting) # "Hi there"
print("Ha" * 3) # "HaHaHa"
+。每次拼接都会创建新字符串,O(n²) 的复杂度。用 ''.join(list),线性时间,快得多。我在处理日志文件时深有体会。
拼接操作要求两边类型一致。列表不能直接拼字符串,会报 TypeError。我见过有人写 [1, 2] + "3",然后一脸懵。
3.4 成员资格检查:in 与 not in
检查一个元素是否在序列里,用 in 或 not in。返回布尔值。
fruits = ["apple", "banana", "cherry"]
print("apple" in fruits) # True
print("grape" in fruits) # False
print("grape" not in fruits) # True
字符串的 in 检查的是子串,不是单个字符。这个区别很重要。
text = "Hello, Python!"
print("Python" in text) # True
print("hello" in text) # False,大小写敏感
if item in seq:,别写 if seq.count(item) > 0:。前者清晰,后者又慢又啰嗦。
对于列表和元组,in 是线性扫描,O(n)。对于集合和字典,是哈希查找,O(1)。如果你频繁做成员检查,把列表转成集合能大幅提升性能。我在做数据去重时经常这么干。
3.5 知识结构总览
下面这张图把序列通用操作的核心逻辑串起来了。你一看就明白。
3.6 操作对比速查表
我把四种操作的关键点整理成了一张表。写代码时拿不准,扫一眼就行。
| 操作 | 语法 | 返回值 | 常见坑 |
|---|---|---|---|
| 索引 | seq[i] |
单个元素 | 越界抛 IndexError |
| 切片 | seq[start:stop:step] |
新序列(浅拷贝) | 左闭右开,容易多取或少取一位 |
| 拼接 | seq1 + seq2 |
新序列 | 类型必须一致;大量拼接用 join |
| 重复 | seq * n |
新序列 | n 为 0 或负数返回空序列 |
| 成员检查 | x in seq |
布尔值 | 列表/元组是 O(n),频繁检查建议用集合 |
好了,序列通用操作就这些。索引和切片是基本功,拼接和重复是日常工具,成员检查是条件判断的常客。你想想看,是不是每个 Python 程序里都少不了它们?
我个人建议,把这四种操作练到肌肉记忆。写代码时不用想,手就自然敲出来了。这样你才能把注意力放在更复杂的逻辑上。