序列是支持索引、切片、len()和迭代的有序容器,核心在于实现__getitem__和__len__方法;list可变,tuple不可变但可含可变对象;str是不可变Unicode序列;range是惰性整数序列。

序列的本质是支持索引和切片的有序容器
Python 中的 list、tuple、str、bytes、range 都是序列类型,根本特征不是“能放多个值”,而是实现了 __getitem__ 和 __len__,从而支持 [i] 索引、[start:stop:step] 切片、len()、for x in seq: 迭代等共性操作。比如 range(5)[2] 能取到 2,range(5)[1:4] 返回 range(1, 4) —— 它没存所有数,但行为符合序列协议。
列表和元组的关键差异在可变性与内存模型
列表是可变序列(list),支持 .append()、.pop()、[i] = x;元组是不可变序列(tuple),创建后不能增删改元素。注意:不可变 ≠ 所有嵌套对象都不可变。例如 t = ([1], 2) 是合法元组,t[0].append(3) 不报错,因为变的是列表对象本身,元组里存的只是对它的引用。
- 函数参数默认用
tuple接收多余位置参数:def f(*args):→args是tuple -
dict.keys()在 Python 3.7+ 返回dict_keys视图,不是序列;想切片得先转成list(d.keys()) - 元组作为字典键可用,列表不行:
{(1, 2): 'ok'}合法,{[1, 2]: 'bad'}报TypeError: unhashable type: 'list'
字符串是不可变的字符序列,不是“字符数组”
str 行为上像只读元组,但底层是 Unicode 码点序列,不是字节数组。所以 'abc'[1] 返回 'b'(仍是 str 类型),不是 int 或 bytes;'abc'[1:2] 也是 str,不是单个字符类型。常见误区:
- 误以为
s[0]是 ASCII 值:实际是长度为 1 的字符串,要转数字得用ord(s[0]) - 用
+=拼接大量字符串性能差:每次都会新建对象,应改用''.join(list_of_str) -
str支持.encode()得bytes,但bytes切片返回仍是bytes,不是int;要取单个字节整数值,得用b[0](Python 3)
别把 range 当作“轻量 list”,它不存储全部值
range 是惰性序列,只存 start/stop/step 三个数和长度逻辑,len(range(10**10)) 瞬间返回,而 list(range(10**10)) 直接爆内存。但它不支持任意对象索引——只能用整数,且不支持 .append() 等方法。容易踩坑的点:
立即学习“Python免费学习笔记(深入)”;
-
range(5) == range(0, 5)为True,但range(0, 5, 1) is not range(0, 5)(不同对象) -
list(range(1, 6))[::2]得[1, 3, 5];但range(1, 6)[::2]得range(1, 6, 2),仍是range对象 - 传给需要“真列表”的函数(如
numpy.array())时,必须显式调用list(),否则可能触发意外行为
序列协议看着简单,但跨类型混用时(比如把 range 当 list 用、对 str 做 .append)出错往往不直观。最稳妥的做法是:先用 isinstance(x, collections.abc.Sequence) 检查,再按需转换,而不是依赖鸭子类型硬刚。











