2025-10-08 Python 标准库 8——内置类型:集合与字典
文章目录
1. 集合类型 — set, frozenset
集合是 Python 中用于存储唯一、无序元素的容器类型,核心价值在于高效的成员检测、去重和数学集合运算(如交集、并集)。Python 提供两种集合类型:set(可变)和 frozenset(不可变),二者特性与适用场景不同,需根据需求选择。
1.1. 集合特性
- 唯一性:集合内元素不可重复,自动过滤重复值(元素需为
hashable类型,如整数、字符串、元组,列表、字典等可变类型不可作为集合元素); - 无序性:集合不记录元素插入顺序,不支持索引、切片等序列操作;
- 可变性差异:
set:可变,支持添加/删除元素,但因可变导致无哈希值,不能作为字典键或其他集合的元素;frozenset:不可变,创建后无法修改元素,支持哈希,可作为字典键或其他集合的元素。
1.2. 创建方式
1.2.1. set 创建
set 有三种常见创建方式,推荐优先使用花括号(注意:空集合不能用 {},需用 set(),因 {} 表示空字典):
# 1. 花括号(非空集合):自动去重
s1 = {1, 2, 2, 3}
print(s1) # 输出:{1, 2, 3}(重复的 2 被过滤)
# 2. 集合推导式:按条件生成集合
s2 = {c for c in 'abracadabra' if c not in 'abc'}
print(s2) # 输出:{'d', 'r'}(排除 'a'/'b'/'c',去重后剩余 'd'/'r')
# 3. 构造器 set(iterable):接收可迭代对象(如列表、字符串)
s3 = set([1, 2, 3]) # 列表转集合
s4 = set('hello') # 字符串转集合(字符去重)
print(s3) # 输出:{1, 2, 3}
print(s4) # 输出:{'h', 'e', 'l', 'o'}('l' 重复被过滤)
# 注意:空集合必须用 set(),不能用 {}
empty_set = set()
print(type(empty_set)) # 输出:<class 'set'>
print(type({})) # 输出:<class 'dict'>(空字典)
1.2.2. frozenset 创建
frozenset 仅支持通过构造器 frozenset(iterable) 创建(无花括号语法),因不可变,创建后无法修改元素:
# 1. 构造器创建:接收可迭代对象
fs1 = frozenset([1, 2, 2, 3]) # 列表转冻结集合(自动去重)
fs2 = frozenset('hello') # 字符串转冻结集合
print(fs1) # 输出:frozenset({1, 2, 3})
print(fs2) # 输出:frozenset({'h', 'e', 'l', 'o'})
# 2. 冻结集合可作为字典键(因可哈希)
dict_with_fs = {fs1: 'value'}
print(dict_with_fs) # 输出:{frozenset({1, 2, 3}): 'value'}
# 错误:冻结集合不可修改
# fs1.add(4) # 报错:AttributeError: 'frozenset' object has no attribute 'add'
1.3. 集合通用操作
set 和 frozenset 均支持成员检测、长度计算和数学集合运算,运算可通过方法或运算符实现(方法支持任意可迭代对象,运算符仅支持集合对象)。
1.3.1. 基础操作(成员检测、长度)
| 操作 | 功能描述 | 示例代码 | 输出结果 |
|---|---|---|---|
len(s) |
返回集合元素个数 | len({1,2,3}) |
3 |
x in s |
检测 x 是否为集合成员 | 2 in {1,2,3} |
True |
x not in s |
检测 x 是否非集合成员 | 4 not in {1,2,3} |
True |
s.isdisjoint(other) |
检测 s 与 other 是否无交集 | {1,2}.isdisjoint({3,4}) |
True |
s = {1, 2, 3, 4}
other = {3, 4, 5}
# 成员检测
print(2 in s) # 输出:True
print(5 not in s) # 输出:True
# 无交集检测
print(s.isdisjoint(other)) # 输出:False(有交集 {3,4})
print(s.isdisjoint({5,6})) # 输出:True(无交集)
1.3.2. 子集与超集检测
| 方法/运算符 | 功能描述 | 示例代码 | 输出结果 |
|---|---|---|---|
s.issubset(other) / s <= other |
检测 s 是否为 other 的子集 | {1,2} <= {1,2,3} |
True |
s < other |
检测 s 是否为 other 的真子集(s <= other 且 s != other) | {1,2} < {1,2,3} |
True |
s.issuperset(other) / s >= other |
检测 s 是否为 other 的超集 | {1,2,3} >= {1,2} |
True |
s > other |
检测 s 是否为 other 的真超集 | {1,2,3} > {1,2} |
True |
s1 = {1, 2}
s2 = {1, 2, 3}
# 子集检测
print(s1.issubset(s2)) # 输出:True
print(s1 <= s2) # 输出:True
print(s1 < s2) # 输出:True(真子集,s1 != s2)
# 超集检测
print(s2.issuperset(s1)) # 输出:True
print(s2 >= s1) # 输出:True
print(s2 > s1) # 输出:True(真超集)
# 非子集/超集
print(s2 <= s1) # 输出:False
1.3.3. 数学集合运算(并、交、差、对称差)
集合运算返回新集合,不修改原集合,set 和 frozenset 运算结果类型与第一个操作数一致(如 frozenset | set 返回 frozenset)。
| 运算类型 | 方法 | 运算符 | 功能描述 |
|---|---|---|---|
| 并集 | s.union(*others) |
`s | other` |
| 交集 | s.intersection(*others) |
s & other |
保留 s 与 others 共有的元素 |
| 差集 | s.difference(*others) |
s - other |
保留 s 中不在 others 中的元素 |
| 对称差集 | s.symmetric_difference(other) |
s ^ other |
保留仅在 s 或仅在 other 中的元素(排除共有的) |
s1 = {1, 2, 3}
s2 = {3, 4, 5}
s3 = {5, 6, 7}
# 1. 并集:合并所有元素
print(s1.union(s2, s3)) # 输出:{1,2,3,4,5,6,7}(方法支持多个参数)
print(s1 | s2 | s3) # 输出:{1,2,3,4,5,6,7}(运算符需逐个连接)
# 2. 交集:保留共有元素
print(s1.intersection(s2)) # 输出:{3}(s1 与 s2 共有)
print(s1 & s2 & s3) # 输出:set()(三者无共有元素)
# 3. 差集:保留 s1 中不在 s2/s3 的元素
print(s1.difference(s2, s3)) # 输出:{1,2}(排除 3/5/6/7)
print(s1 - s2) # 输出:{1,2}(排除 3)
# 4. 对称差集:保留仅在一方的元素
print(s1.symmetric_difference(s2)) # 输出:{1,2,4,5}(排除 3)
print(s1 ^ s2) # 输出:{1,2,4,5}
# 5. 冻结集合与普通集合运算(结果类型与第一个操作数一致)
fs = frozenset({1,2})
print(type(fs | s1)) # 输出:<class 'frozenset'>(第一个操作数是 frozenset)
print(type(s1 | fs)) # 输出:<class 'set'>(第一个操作数是 set)
1.3.4. 拷贝操作(copy())
返回集合的浅拷贝(因集合元素是 hashable,浅拷贝已满足需求):
s = {1, 2, 3}
s_copy = s.copy()
print(s_copy) # 输出:{1,2,3}
print(s is s_copy) # 输出:False(不同对象,浅拷贝)
1.4. set 独有的可变操作
frozenset 不可修改,仅 set 支持添加、删除元素等可变操作,这些操作均为原地修改(无返回值或返回被修改的元素)。
1.4.1. 批量更新元素(update 系列)
| 方法 | 运算符 | 功能描述 |
|---|---|---|
s.update(*others) |
`s | = other` |
s.intersection_update(*others) |
s &= other |
仅保留 s 与 others 共有的元素,删除其他元素 |
s.difference_update(*others) |
s -= other |
删除 s 中在 others 中的元素 |
s.symmetric_difference_update(other) |
s ^= other |
原地更新 s 为“仅在 s 或仅在 other 中的元素” |
s = {1, 2, 3}
# 1. update:添加元素
s.update([3, 4, 5]) # 方法支持可迭代对象
print(s) # 输出:{1,2,3,4,5}(3 已存在,不重复添加)
s |= {5, 6, 7} # 运算符支持集合
print(s) # 输出:{1,2,3,4,5,6,7}
# 2. intersection_update:保留交集
s.intersection_update({4,5,6})
print(s) # 输出:{4,5,6}(仅保留与 {4,5,6} 共有的元素)
# 3. difference_update:删除指定元素
s.difference_update([5])
print(s) # 输出:{4,6}(删除 5)
# 4. symmetric_difference_update:更新为对称差
s ^= {6,7,8}
print(s) # 输出:{4,7,8}(仅保留 4 或 7/8,排除 6)
1.4.2. 单个元素操作(add、remove、discard、pop)
| 方法 | 功能描述 | 注意事项 |
|---|---|---|
s.add(elem) |
向 s 中添加元素 elem | 若 elem 已存在,无操作(不报错) |
s.remove(elem) |
从 s 中删除元素 elem | 若 elem 不存在,引发 KeyError |
s.discard(elem) |
从 s 中删除元素 elem(若存在) | 若 elem 不存在,无操作(不报错) |
s.pop() |
从 s 中随机删除并返回一个元素 | 若 s 为空,引发 KeyError(集合无序,“随机”实际是底层存储顺序) |
s = {1, 2, 3}
# 1. add:添加元素
s.add(4)
print(s) # 输出:{1,2,3,4}
s.add(3) # 3 已存在,无操作
print(s) # 输出:{1,2,3,4}
# 2. remove:删除存在的元素
s.remove(3)
print(s) # 输出:{1,2,4}
# s.remove(5) # 报错:KeyError: 5(5 不存在)
# 3. discard:删除元素(不存在不报错)
s.discard(4)
print(s) # 输出:{1,2}
s.discard(5) # 5 不存在,无操作
print(s) # 输出:{1,2}
# 4. pop:随机删除并返回元素
elem = s.pop()
print(elem) # 输出:1 或 2(随机,取决于底层存储)
print(s) # 输出:{2} 或 {1}
# 清空集合
s.clear()
print(s) # 输出:set()
# s.pop() # 报错:KeyError: 'pop from an empty set'
1.5. 集合的比较与排序
- 相等比较:两个集合当且仅当元素完全相同(无顺序差异)时相等,
set与frozenset也可比较(如set({1,2}) == frozenset({1,2})返回True); - 部分排序:仅支持子集/超集比较(
<=、>=、<、>),非子集/超集的集合无法比较大小(如{1,2} > {3,4}返回False,而非True或False有明确含义); - 无全局排序:因集合无序,
list.sort()对集合列表排序无定义(输出顺序不可预测)。
s1 = {1, 2}
s2 = {2, 1}
fs = frozenset({1, 2})
s3 = {3, 4}
# 相等比较(元素相同即相等,与类型无关)
print(s1 == s2) # 输出:True(元素相同,顺序无关)
print(s1 == fs) # 输出:True(set 与 frozenset 元素相同)
# 部分排序(子集/超集)
print(s1 <= s2) # 输出:True(s1 是 s2 的子集)
print(s1 < {1,2,3}) # 输出:True(s1 是真子集)
# 非子集/超集的比较(无意义,返回 False)
print(s1 > s3) # 输出:False
print(s1 < s3) # 输出:False
2. 映射类型 — dict
字典(dict)是 Python 中唯一的内置映射类型,用于存储键值对(key-value),核心特性是通过 hashable 键快速查找值(平均时间复杂度 O(1)),Python 3.7+ 版本开始保留键的插入顺序。
2.1. 字典特性
- 键值对结构:每个键(key)映射一个值(value),键需为
hashable类型(如整数、字符串、元组),值可任意(包括列表、字典等可变类型); - 键唯一性:字典内键不可重复,重复赋值会覆盖原有值;
- 插入顺序保留:Python 3.7+ 版本保证键的插入顺序,
popitem()按 LIFO(后进先出)顺序删除键值对; - 动态性:支持添加、修改、删除键值对,无需预先指定大小。
2.2. 创建方式
字典有多种创建方式,可根据场景选择最简洁的形式:
2.2.1. 花括号语法({key: value, ...})
最常用的创建方式,直接指定键值对,键需符合 hashable 要求:
# 基础键值对(字符串键)
d1 = {'name': 'Alice', 'age': 25}
print(d1) # 输出:{'name': 'Alice', 'age': 25}
# 非字符串键(整数、元组)
d2 = {1: 'one', (2, 3): 'two-three'}
print(d2) # 输出:{1: 'one', (2, 3): 'two-three'}
# 重复键:后值覆盖前值
d3 = {'a': 1, 'a': 2}
print(d3) # 输出:{'a': 2}(重复键被覆盖)
2.2.2. 字典推导式({key_expr: value_expr for ...})
通过循环和条件生成字典,语法简洁,适合动态构建:
# 1. 基础推导式:键值均为表达式
d1 = {x: x**2 for x in range(5)} # 键为 0~4,值为平方
print(d1) # 输出:{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 2. 带条件的推导式
d2 = {x: x*2 for x in range(10) if x % 2 == 0} # 仅偶数键
print(d2) # 输出:{0: 0, 2: 4, 4: 8, 6: 12, 8: 16}
# 3. 从两个列表生成(用 zip 配对)
keys = ['a', 'b', 'c']
values = [1, 2, 3]
d3 = {k: v for k, v in zip(keys, values)}
print(d3) # 输出:{'a': 1, 'b': 2, 'c': 3}
2.2.3. 构造器 dict()
构造器支持多种参数形式,灵活适配不同输入场景:
# 1. 空字典
d1 = dict()
print(d1) # 输出:{}
# 2. 键值对参数(键需为有效标识符)
d2 = dict(name='Bob', age=30) # 等价于 {'name': 'Bob', 'age': 30}
print(d2) # 输出:{'name': 'Bob', 'age': 30}
# 3. 可迭代对象(元素为长度 2 的可迭代对象,如元组、列表)
d3 = dict([('a', 1), ('b', 2)]) # 列表内元组为键值对
d4 = dict(((1, 'one'), (2, 'two'))) # 元组内元组为键值对
print(d3) # 输出:{'a': 1, 'b': 2}
print(d4) # 输出:{1: 'one', 2: 'two'}
# 4. 其他字典(复制)
d5 = dict(d2) # 复制 d2 的键值对
print(d5) # 输出:{'name': 'Bob', 'age': 30}
# 5. 混合参数(位置参数 + 关键字参数,关键字参数覆盖位置参数)
d6 = dict([('name', 'Alice')], age=25) # 关键字参数 age 覆盖位置参数(若有)
print(d6) # 输出:{'name': 'Alice', 'age': 25}
2.2.4. 类方法 fromkeys()
通过可迭代对象生成字典,所有键的默认值为 None(或指定值),需注意值为可变对象时的共享陷阱:
# 1. 基础用法:默认值 None
keys = ['a', 'b', 'c']
d1 = dict.fromkeys(keys)
print(d1) # 输出:{'a': None, 'b': None, 'c': None}
# 2. 指定默认值
d2 = dict.fromkeys(keys, 0) # 所有键值为 0
print(d2) # 输出:{'a': 0, 'b': 0, 'c': 0}
# 3. 陷阱:可变值会被所有键共享(如空列表)
d3 = dict.fromkeys(keys, []) # 所有键共享同一个列表
d3['a'].append(1) # 修改 'a' 的值,所有键的值都会变
print(d3) # 输出:{'a': [1], 'b': [1], 'c': [1]}
# 解决陷阱:用字典推导式生成独立值
d4 = {k: [] for k in keys} # 每个键对应新列表
d4['a'].append(1)
print(d4) # 输出:{'a': [1], 'b': [], 'c': []}
2.3. 字典的基础操作
2.3.1. 访问键值对(d[key]、d.get())
d[key]:直接访问键key对应的值,键不存在时引发KeyError;d.get(key, default=None):安全访问,键不存在时返回default(默认None),不引发异常。
d = {'name': 'Alice', 'age': 25}
# 1. 直接访问(键存在)
print(d['name']) # 输出:Alice
# 2. 直接访问(键不存在,报错)
# print(d['gender']) # 报错:KeyError: 'gender'
# 3. get 方法(键不存在,返回默认值)
print(d.get('gender')) # 输出:None(默认值)
print(d.get('gender', 'female')) # 输出:female(指定默认值)
2.3.2. 修改键值对(d[key] = value)
- 键存在:覆盖原有值;
- 键不存在:添加新键值对。
d = {'name': 'Alice', 'age': 25}
# 1. 修改已有键
d['age'] = 26
print(d) # 输出:{'name': 'Alice', 'age': 26}
# 2. 添加新键
d['gender'] = 'female'
print(d) # 输出:{'name': 'Alice', 'age': 26, 'gender': 'female'}
2.3.3. 删除键值对(del、d.pop()、d.popitem()、d.clear())
| 操作 | 功能描述 | 示例代码 | 输出结果 |
|---|---|---|---|
del d[key] |
删除键 key 对应的键值对,键不存在引发 KeyError |
del d['age'](d 为 {‘age’:25}) |
-(无返回值) |
d.pop(key, default) |
删除键 key 并返回其值,键不存在时返回 default(无 default 则引发 KeyError) |
d.pop('age', 0)(d 无 ‘age’) |
0 |
d.popitem() |
按 LIFO 顺序删除并返回最后插入的键值对(Python 3.7+),空字典引发 KeyError |
d.popitem()(d 为 {‘a’:1,‘b’:2}) |
('b', 2) |
d.clear() |
删除所有键值对,清空字典 | d.clear()(d 为 {‘a’:1}) |
-(无返回值) |
d = {'name': 'Alice', 'age': 25, 'gender': 'female'}
# 1. del:删除指定键
del d['gender']
print(d) # 输出:{'name': 'Alice', 'age': 25}
# del d['height'] # 报错:KeyError: 'height'
# 2. pop:删除并返回值
age = d.pop('age')
print(age) # 输出:25
height = d.pop('height', 160) # 键不存在,返回默认值 160
print(height) # 输出:160
print(d) # 输出:{'name': 'Alice'}
# 3. popitem:LIFO 删除最后插入的键值对
d['age'] = 25
d['gender'] = 'female'
last_item = d.popitem()
print(last_item) # 输出:('gender', 'female')(最后插入的键)
print(d) # 输出:{'name': 'Alice', 'age': 25}
# 4. clear:清空字典
d.clear()
print(d) # 输出:{}
2.4. 字典的常用方法
2.4.1. d.setdefault(key, default=None)
- 键存在:返回键对应的值,不修改字典;
- 键不存在:添加键值对
(key: default)并返回default(默认None),适合“获取或初始化”场景。
d = {'name': 'Alice', 'hobbies': ['reading']}
# 1. 键存在:返回现有值
hobbies = d.setdefault('hobbies', [])
print(hobbies) # 输出:['reading']
hobbies.append('hiking') # 修改返回的列表,字典值也会变
print(d) # 输出:{'name': 'Alice', 'hobbies': ['reading', 'hiking']}
# 2. 键不存在:添加并返回默认值
gender = d.setdefault('gender', 'female')
print(gender) # 输出:female
print(d) # 输出:{'name': 'Alice', 'hobbies': [...], 'gender': 'female'}
2.4.2. d.update()
批量更新字典,支持三种参数形式,已有键会被覆盖,新键会被添加:
- 关键字参数:
d.update(key1=value1, key2=value2)(键需为有效标识符); - 映射对象:
d.update(other_dict)(如其他字典); - 可迭代对象:
d.update(iterable)(元素为长度 2 的可迭代对象,如[(k1,v1), (k2,v2)])。
d = {'name': 'Alice', 'age': 25}
# 1. 关键字参数更新
d.update(age=26, gender='female')
print(d) # 输出:{'name': 'Alice', 'age': 26, 'gender': 'female'}
# 2. 映射对象更新(其他字典)
other_dict = {'gender': 'F', 'height': 160}
d.update(other_dict)
print(d) # 输出:{'name': 'Alice', 'age': 26, 'gender': 'F', 'height': 160}
# 3. 可迭代对象更新(列表内元组)
iterable = [('weight', 50), ('hobby', 'reading')]
d.update(iterable)
print(d) # 输出:{'name': 'Alice', 'age': 26, 'gender': 'F', 'height': 160, 'weight': 50, 'hobby': 'reading'}
2.5. 字典的合并与更新(|、|=)
Python 3.9+ 版本新增字典合并运算符 | 和原地更新运算符 |=,简化字典合并操作:
d1 | d2:返回新字典,合并d1和d2的键值对,d2的键覆盖d1的重复键;d1 |= d2:原地更新d1,合并d2的键值对,d2的键覆盖d1的重复键(d2可为映射对象或可迭代的键值对)。
# 1. 合并运算符 |(返回新字典)
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
merged = d1 | d2
print(merged) # 输出:{'a': 1, 'b': 3, 'c': 4}(d2 的 'b' 覆盖 d1 的)
print(d1) # 输出:{'a': 1, 'b': 2}(原字典不变)
# 2. 原地更新运算符 |=
d1 |= d2
print(d1) # 输出:{'a': 1, 'b': 3, 'c': 4}(d1 被更新)
# 3. |= 支持可迭代的键值对(如列表)
d1 |= [('d', 5), ('e', 6)]
print(d1) # 输出:{'a': 1, 'b': 3, 'c': 4, 'd': 5, 'e': 6}
2.6. 字典视图对象
字典的 keys()、values()、items() 方法返回视图对象(而非列表),视图对象具有以下特性:
- 动态性:视图会实时反映字典的变化(字典修改后,视图自动更新);
- 不可修改:视图对象本身不可修改(如无法添加/删除元素);
- 支持迭代与成员检测:可循环遍历,也可使用
in检测成员; - 键视图与项视图支持集合运算:因键唯一且可哈希,键视图(
d.keys())和项视图(d.items(),需值也可哈希)支持交集、并集等集合操作。
2.6.1. 视图对象的基础使用
d = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
# 1. 获取视图对象
keys_view = d.keys() # 键视图
values_view = d.values()# 值视图
items_view = d.items() # 项视图(元素为 (key, value) 元组)
# 2. 迭代视图
print('迭代键视图:', end='')
for k in keys_view:
print(k, end=' ') # 输出:迭代键视图:eggs sausage bacon spam
print('\n迭代项视图:', end='')
for k, v in items_view:
print(f'({k}:{v})', end=' ') # 输出:迭代项视图:(eggs:2) (sausage:1) (bacon:1) (spam:500)
# 3. 动态性:修改字典,视图自动更新
del d['eggs'] # 删除键 'eggs'
print('\n修改后键视图:', list(keys_view)) # 输出:修改后键视图:['sausage', 'bacon', 'spam']
# 4. 成员检测
print('spam' in keys_view) # 输出:True(键视图检测键)
print(500 in values_view) # 输出:True(值视图检测值)
print(('bacon', 1) in items_view) # 输出:True(项视图检测 (key, value))
2.6.2. 视图对象的集合运算(键视图/项视图)
仅键视图和项视图(值可哈希时)支持集合运算,值视图因值可能重复,不支持集合运算:
d1 = {'a': 1, 'b': 2, 'c': 3}
d2 = {'b': 2, 'c': 4, 'd': 5}
# 1. 键视图的集合运算
keys1 = d1.keys()
keys2 = d2.keys()
print(keys1 & keys2) # 输出:{'b', 'c'}(交集:共有的键)
print(keys1 | keys2) # 输出:{'a', 'b', 'c', 'd'}(并集:所有键)
print(keys1 - keys2) # 输出:{'a'}(差集:d1 独有的键)
# 2. 项视图的集合运算(需值可哈希)
items1 = d1.items()
items2 = d2.items()
print(items1 & items2) # 输出:{('b', 2)}(交集:共有的 (key, value))
print(items1 - items2) # 输出:{('a', 1), ('c', 3)}(差集:d1 独有的项)
2.6.3. 视图对象的 mapping 属性(Python 3.10+)
视图对象的 mapping 属性返回字典的只读代理(types.MappingProxyType),可访问字典值但无法修改:
d = {'spam': 500, 'bacon': 1}
values_view = d.values()
# 获取只读代理
proxy = values_view.mapping
print(proxy['spam']) # 输出:500(可访问值)
# 只读代理不可修改
# proxy['spam'] = 600 # 报错:TypeError: 'mappingproxy' object does not support item assignment
2.7. 自定义字典的 __missing__ 方法
字典的子类可通过定义 __missing__(key) 方法,自定义键不存在时的行为(d[key] 访问不存在的键时,会调用该方法,而非直接引发 KeyError)。dict 基类无此方法,需手动实现。
模拟 collections.Counter 的部分功能(键不存在时返回 0):
class Counter(dict):
def __missing__(self, key):
# 键不存在时返回 0
return 0
# 使用自定义 Counter
c = Counter()
print(c['red']) # 输出:0(键 'red' 不存在,调用 __missing__ 返回 0)
# 赋值后正常访问
c['red'] += 1
print(c['red']) # 输出:1(键已存在,不调用 __missing__)
# 其他操作(如 get)不触发 __missing__
print(c.get('blue')) # 输出:None(get 方法不调用 __missing__)
2.8. 字典的其他特性
- 可逆性(Python 3.8+):支持
reversed(d),返回逆序的键迭代器(按插入顺序逆序); - 值的比较:
dict.values()视图之间的比较始终返回False(即使值完全相同),需转换为列表后比较; - 只读字典:可通过
types.MappingProxyType创建字典的只读视图,防止意外修改。
# 1. 可逆性
d = {'a': 1, 'b': 2, 'c': 3}
print(list(reversed(d))) # 输出:['c', 'b', 'a'](键逆序)
print(list(reversed(d.items()))) # 输出:[('c', 3), ('b', 2), ('a', 1)](项逆序)
# 2. 值视图比较(始终返回 False)
d1 = {'a': 1, 'b': 2}
d2 = {'a': 1, 'b': 2}
print(d1.values() == d2.values()) # 输出:False
print(list(d1.values()) == list(d2.values())) # 输出:True(转换为列表后比较)
# 3. 只读字典(MappingProxyType)
from types import MappingProxyType
d = {'a': 1}
readonly_d = MappingProxyType(d)
print(readonly_d['a']) # 输出:1(可访问)
# readonly_d['a'] = 2 # 报错:TypeError: 'mappingproxy' object does not support item assignment
d['a'] = 2 # 修改原字典,只读视图同步更新
print(readonly_d['a']) # 输出:2
3. 总结
-
集合类型:
set可变,适合动态去重和集合运算,不可作为字典键;frozenset不可变,支持哈希,可作为字典键或集合元素,适合存储固定唯一数据;- 核心优势是高效的成员检测(O(1))和自动去重,避免使用集合进行排序(无序)。
-
映射类型(dict):
- 核心是键值对结构,键需
hashable,值可任意,Python 3.7+ 保留插入顺序; - 常用操作:访问(
get()安全,[]直接)、修改(d[key] = value)、合并(|、update()); - 视图对象动态反映字典变化,键视图/项视图支持集合运算,适合批量处理键值对;
- 自定义
__missing__方法可扩展键不存在时的行为,满足特殊需求(如默认值)。
- 核心是键值对结构,键需
掌握集合与字典的特性和操作,能大幅提升数据去重、查找和映射场景的代码效率,是 Python 开发的基础技能。
更多推荐



所有评论(0)