参考文档:内置类型 — Python 3.13.7 文档

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. 集合通用操作

setfrozenset 均支持成员检测、长度计算和数学集合运算,运算可通过方法运算符实现(方法支持任意可迭代对象,运算符仅支持集合对象)。

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. 数学集合运算(并、交、差、对称差)

集合运算返回新集合,不修改原集合,setfrozenset 运算结果类型与第一个操作数一致(如 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. 单个元素操作(addremovediscardpop

方法 功能描述 注意事项
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. 集合的比较与排序

  • 相等比较:两个集合当且仅当元素完全相同(无顺序差异)时相等,setfrozenset 也可比较(如 set({1,2}) == frozenset({1,2}) 返回 True);
  • 部分排序:仅支持子集/超集比较(<=>=<>),非子集/超集的集合无法比较大小(如 {1,2} > {3,4} 返回 False,而非 TrueFalse 有明确含义);
  • 无全局排序:因集合无序,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. 删除键值对(deld.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()

批量更新字典,支持三种参数形式,已有键会被覆盖,新键会被添加

  1. 关键字参数:d.update(key1=value1, key2=value2)(键需为有效标识符);
  2. 映射对象:d.update(other_dict)(如其他字典);
  3. 可迭代对象: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:返回新字典,合并 d1d2 的键值对,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 开发的基础技能。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐