容器类型
约 2051 字大约 7 分钟
2026-05-27
容器用来装多个对象。Python 内置里最常用的是 list / tuple / dict / set;str 也是不可变有序字符序列,很多序列操作与 list 相通
| 类型 | 可变 | 有序 | 元素可重复 | 典型场景 |
|---|---|---|---|---|
list | 是 | 是 | 是 | 通用序列、栈队列 |
tuple | 否 | 是 | 是 | 固定结构、多返回值、可作 dict 键 |
dict | 是 | 是(3.7+ 保序) | 键唯一 | 映射、记录 |
set | 是 | 否 | 否 | 去重、集合运算 |
str | 否 | 是 | 是(字符) | 文本 |
"有序" 指有稳定的位置语义(索引 / 插入顺序),不是 "自动排序"
列表 list
可变有序序列,元素类型可以混用
创建列表
nums: list[int] = [1, 2, 3]
mixed: list[object] = [1, "hello", 3.14, True, None]
chars = list("abc") # ['a', 'b', 'c']
print(nums, mixed, chars)索引与切片
索引与切片
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]
print(fruits[0], fruits[-1]) # 苹果 西瓜
print(fruits[1:4]) # ['香蕉', '橙子', '葡萄'],左闭右开
print(fruits[:3], fruits[2:])
print(fruits[::2]) # 步长 2
print(fruits[::-1]) # 反转得到新列表切片总是返回新序列,不修改原对象;对 list 赋值切片可以改内容
常用方法
列表增删查与排序
nums = [1, 2, 3]
nums.append(4) # 末尾追加
nums.insert(0, 0) # 指定下标插入
nums.extend([5, 6]) # 拼接可迭代对象
print(nums)
nums.remove(0) # 删第一个等于该值的元素
last = nums.pop() # 弹出末尾
first = nums.pop(0) # 弹出指定下标
del nums[0]
print(last, first, nums)
nums = [1, 2, 3, 2, 4]
print(nums.index(2)) # 1
print(nums.count(2)) # 2
nums = [3, 1, 4, 1, 5]
nums.sort() # 原地排序
print(nums)
nums.sort(reverse=True)
nums.reverse() # 原地反转
print(nums)
print(sorted([3, 1, 4])) # 返回新列表,原列表不动append 加一个元素;extend / + 拼一段。list.append([1,2]) 会把整个列表当成一个元素
元组 tuple
不可变有序序列。创建后不能改元素绑定(元素若是可变对象,其内部仍可改——这是 "元组不可变" 的常见误解点)
创建元组
point: tuple[int, int] = (1, 2)
point2 = 1, 2 # 逗号才是元组的关键
single = (1,) # 单元素必须有逗号
empty = ()
t = tuple([1, 2, 3])
print(point, point2, single, empty, t)
print(type(single), type((1))) # tuple vs int元组索引与查询
t = (1, 2, 3, 2, 4)
print(t[0], t[1:3], t.count(2), t.index(3))
# t[0] = 100 # TypeError解包
元组解包
a, b, c = (1, 2, 3)
print(a, b, c)
head, *mid, tail = (1, 2, 3, 4, 5)
print(head, mid, tail) # 1 [2, 3, 4] 5
x, y = 10, 20
x, y = y, x # 交换本质是元组打包/解包
print(x, y)函数多返回值、固定字段的小记录,优先用 tuple(或后续的 dataclass / NamedTuple)
字典 dict
键值映射。键必须可哈希(一般是不可变对象);值任意
创建字典
person: dict[str, object] = {
"name": "Alice",
"age": 25,
}
person2 = dict(name="Bob", age=30)
keys_only = dict.fromkeys(["a", "b", "c"], 0)
print(person)
print(person2)
print(keys_only)访问与修改
字典读写与删除
person: dict[str, object] = {"name": "Alice", "age": 25}
print(person["name"])
# person["gender"] # KeyError
print(person.get("gender")) # None
print(person.get("gender", "未知")) # 默认值
person["age"] = 26
person["city"] = "北京"
person.update({"age": 27, "job": "dev"})
print(person)
age = person.pop("age")
del person["job"]
print(age, person)键的哈希与唯一性
ok = {(1, 2): "point"}
print(ok)
# bad = {[1, 2]: "x"} # TypeError: unhashable type: 'list'
# 键唯一,后写覆盖前写
d = {"a": 1, "a": 2}
print(d) # {'a': 2}Python 3.7+ 字典保留插入顺序,遍历顺序稳定,但语义上仍是映射而不是 "列表的替代品"
集合 set
无序不重复,元素须可哈希。适合去重与成员检测
集合创建与增删
s: set[int] = {1, 2, 3, 2}
print(s) # {1, 2, 3}
s2 = set([3, 4, 5])
empty: set[int] = set() # 不能写 {},那是空 dict
print(s2, empty, type({}))
s.add(4)
s.discard(9) # 不存在也不报错
s.remove(1) # 不存在会 KeyError
print(s)集合运算
集合运算
s1, s2 = {1, 2, 3}, {2, 3, 4}
print(s1 & s2) # 交集 {2, 3}
print(s1 | s2) # 并集
print(s1 - s2) # 差集
print(s1 ^ s2) # 对称差
print(s1.intersection(s2))去重保序需要时:list(dict.fromkeys(items)),因为 3.7+ dict 保序而 set 不保序
去重且保序
items = [3, 1, 2, 1, 3]
print(list(dict.fromkeys(items))) # [3, 1, 2]
print(list(set(items))) # 顺序不保证通用操作
内置函数
len / max / min / sum / sorted
print(len([1, 2, 3]), len({"a": 1}))
print(max([3, 1, 4]), min("hello"))
print(sum((1, 2, 3)))
print(sorted({3, 1, 2})) # 总是返回 list
print(list(reversed([1, 2, 3])))成员与连接
in 与连接重复
print(3 in [1, 2, 3])
print("he" in "hello") # 子串
print("name" in {"name": "A"}) # dict 的 in 查的是键
print("A" in {"name": "A"}) # False
print([1, 2] + [3, 4])
print((1, 2) * 2)
# {1} + {2} # TypeError,集合用 | 而不是 +== 与 is
值相等与身份相同
a = [1, 2, 3]
b = a
c = [1, 2, 3]
print(a == c) # True,值相等
print(a is b) # True,同一对象
print(a is c) # False,两个列表
# 和 None 比较永远用 is
value = None
if value is None:
print("空")== 问 "长得一样吗",is 问 "是不是内存里同一个"。小整数 / 短字符串可能被解释器缓存,导致 is 碰巧为真——不要用 is 比较普通值
遍历、enumerate、zip
for / enumerate / zip
for x in [1, 2, 3]:
print(x)
for k, v in {"a": 1, "b": 2}.items():
print(k, v)
for i, name in enumerate(["苹果", "香蕉"], start=1):
print(i, name)
for n, ch in zip([1, 2, 3], "ab"):
print(n, ch) # 以最短为准,只输出两对浅拷贝与共享引用
容器赋值是绑定引用,不是深拷贝
引用共享与浅拷贝
a = [1, 2, 3]
b = a
b.append(4)
print(a) # [1, 2, 3, 4],a 也被改了
c = a.copy() # 或 a[:]
c.append(5)
print(a, c)
nested = [[1], [2]]
shallow = nested.copy()
shallow[0].append(9)
print(nested) # [[1, 9], [2]],内层仍共享需要切断嵌套共享时用 copy.deepcopy
list * n 若元素是可变对象,会 共享同一内层对象;二维表要用推导式逐行新建
list 乘与可变元素
rows = [[0] * 3] * 3
rows[0][0] = 1
print(rows) # 三行都被改了
rows = [[0] * 3 for _ in range(3)]
rows[0][0] = 1
print(rows) # 只有第一行变了可变默认参数也会踩同类问题,见 作用域
切片赋值
对 list 的切片赋值可以一次插入、替换或删除一段
切片赋值
nums = [0, 1, 2, 3, 4, 5]
nums[1:4] = [10, 20] # 用两个元素替换三个位置
print(nums)
nums[2:2] = [7, 8] # 在下标 2 处插入
print(nums)
nums[1:3] = [] # 删除一段
print(nums)
nums[:] = [1, 2, 3] # 清空并换成新内容,对象身份可不变
print(nums)推导式
用一行表达式生成 list / dict / set,可读性通常优于手写 for + append。生成器表达式见后续 迭代器与生成器
列表 / 字典 / 集合推导
squares = [x * x for x in range(6)]
evens = [x for x in range(10) if x % 2 == 0]
print(squares, evens)
# 嵌套:矩阵展平
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [n for row in matrix for n in row]
print(flat)
word_len = {w: len(w) for w in ["hi", "python", "go"]}
print(word_len)
unique_lens = {len(w) for w in ["a", "bb", "ccc", "dd"]}
print(unique_lens)推导式里也可以用 if-else 表达式:[x if x > 0 else 0 for x in nums]。逻辑一复杂就改回普通循环,别硬塞
frozenset
不可变集合,可作 dict 的键或放进另一个 set
frozenset
fs = frozenset([1, 2, 2, 3])
print(fs)
# fs.add(4) # AttributeError
cache_key = {frozenset(["a", "b"]): "ok"}
print(cache_key[frozenset(["b", "a"])]) # 集合无序,内容相同即可dict 的更多写法
setdefault 与合并
# setdefault:键不存在则写入默认值并返回
groups: dict[str, list[int]] = {}
for name, score in [("a", 1), ("b", 2), ("a", 3)]:
groups.setdefault(name, []).append(score)
print(groups)
# 3.9+ 合并字典:| 与 |=
a = {"x": 1, "y": 2}
b = {"y": 9, "z": 3}
print(a | b) # {'x': 1, 'y': 9, 'z': 3},右侧覆盖左侧
a |= {"x": 0}
print(a)
# 3.5+ 解包合并
print({**{"a": 1}, **{"b": 2}, "c": 3})zip 的细节
zip 与 strict
names = ["Alice", "Bob", "Charlie"]
scores = [90, 85]
# 默认以最短为准,多出的元素被丢弃
print(list(zip(names, scores)))
# 3.10+ strict=True:长度不一致直接报错,适合校验数据对齐
try:
list(zip(names, scores, strict=True))
except ValueError as e:
print(type(e).__name__, e)