Skip to content

三、字典与集合(P23–P32) ​

P23 · 知识点:字典创建 ​

【题目】在变量 a 未定义的前提下,下列哪个表达式能正确创建字典?

A. (a: 1) B. {a: 1} C. dict("a", "1") D. dict(a=1)

答案:D

【考点】字典的多种创建方式。

【结论】选 D。dict(a=1) 使用关键字参数形式创建字典,键自动转为字符串 "a",得到 {"a": 1}。

【逐项辨析】 D. dict(a=1):正确。关键字参数形式,等价于 {"a": 1}。 B. {a: 1}:错误。若变量 a 未定义,会抛出 NameError;只有当 a 已被赋值时才以变量值为键。 C. dict("a", "1"):错误。dict() 不接受两个独立的位置参数,正确形式应为 dict([("a", 1)]) 或 dict(a=1)。 A. (a: 1):错误。圆括号内使用冒号是语法错误,Python 不支持此语法。

【知识点】 Python 创建字典的常见方式有以下四种:

  1. 字面值:{"a": 1, "b": 2},最直观常用。
  2. 关键字参数:dict(a=1, b=2),键必须是合法标识符,自动转为字符串。
  3. 可迭代对象:dict([("a", 1), ("b", 2)]),接收包含键值对元组的序列。
  4. fromkeys:dict.fromkeys(["a", "b"], 0),批量初始化同值键,默认值为 None。

注意,关键字参数中的键会被强制转为字符串,且不能是 Python 关键字或非法标识符。若键名包含空格、以数字开头或为保留字,则必须使用字面值或可迭代对象形式。

【记忆锚点】 “dict() 有三招:花括号直接写、关键字传参、序列套元组。”

【易混对比】

创建方式示例适用场景
字面值 {}静态定义,最常用
关键字参数dict(a=1)键为合法标识符时
可迭代对象dict([("a", 1)])动态构建键值对
fromkeysdict.fromkeys("ab", 0)批量初始化同值

换问法:若 a = "x",则 {a: 1} 的结果是什么?答:{"x": 1},此时 a 是已定义变量,以变量值为键。

【自测】 以下代码输出什么?

python
print(dict(a=1, b=2))
print(dict([("c", 3)]))

答:{'a': 1, 'b': 2} 和 {'c': 3}。与第 P24 题连考。

【知识关联】

  • 同库关联:与 P24–P28 字典题群;与 J34(Java HashMap)对照。
  • 实现层:CPython dict 基于哈希表,紧凑有序(Py3.7+ 保证插入序)。
  • 面试追问:① 字典有序吗?② {} 与 dict()?

【拓展延伸】

  • 变式问法:字典推导;dict.fromkeys。
  • 版本差异:Py3.6 实现有序,3.7 语言保证有序。
  • 工程注意点:JSON 映射首选 dict;需要排序遍历用 sorted(d)。

P24 · 知识点:字典键要求 ​

【题目】下列哪个类型可以作为字典的键?

A. 列表 B. 字典 C. 元组 D. 集合

答案:C

【考点】字典键必须是可哈希(不可变)类型。

【结论】选 C。字典的键必须是可哈希对象,元组在元素均可哈希时可作为键。

【逐项辨析】 A. 列表:错误。列表是可变类型,不可哈希,不能作为字典键。 B. 字典:错误。字典是可变类型,不可哈希,不能作为字典键。 C. 元组:正确。元组是不可变类型,只要其所有元素均可哈希,即可作为字典键。 D. 集合:错误。集合是可变类型,不可哈希,不能作为字典键。

【知识点】 可哈希(hashable)对象需满足三个条件:

  1. 生命周期内哈希值不变;
  2. 可与其他对象比较相等;
  3. 相等的对象哈希值必须相同。

Python 内置不可变类型如 int、float、str、tuple、frozenset、bytes 等均可哈希。可变类型如 list、dict、set 因内容可变导致哈希值不稳定,故不可哈希。

可用 hash(obj) 函数测试对象是否可哈希,不可哈希对象调用 hash() 会抛出 TypeError。

元组作为键有特殊限制:若元组包含列表等不可哈希元素,则整个元组不可哈希。例如 hash((1, [2])) 会抛出 TypeError。

【记忆锚点】 “键要哈希找不变,列表字典集合免;元组元素全得稳,嵌套可变也完蛋。”

【易混对比】

类型可变性可哈希能否作字典键
int不可变是能
str不可变是能
tuple不可变元素可哈希则可能(有条件)
list可变否不能
dict可变否不能
set可变否不能
frozenset不可变是能

换问法:t = (1, [2]),能否用 t 作为字典的键?答:不能,因为元组中包含不可哈希的列表,整体不可哈希。

【自测】

python
d = {}
t = (1, "a")
d[t] = 10
print(len(d))

答:1。与第 P25 题连考。

【知识关联】

  • 同库关联:与 P23、P07(可哈希)、J36(Java null key)。
  • 实现层:key 必须可哈希且比较相等语义一致;__hash__ 与 __eq__ 契约。
  • 面试追问:① 列表能否作 key?② 元组何时可以?

【拓展延伸】

  • 变式问法:{(1,2):"a"} 合法;{[1]:"a"} TypeError。
  • 版本差异:语义稳定。
  • 工程注意点:自定义对象作 key 要冻结字段;frozenset 可作 key。

P25 · 知识点:get 与下标取值 ​

【题目】d = {"a": 1},d.get("b") 和 d["b"] 的结果分别是?

A. None 和 None B. 都抛 KeyError C. 都是 None D. None 和抛 KeyError

答案:D

【考点】字典取值的安全方式:get 带默认值,下标不存在抛 KeyError。

【结论】选 D。d.get("b") 返回 None,d["b"] 抛出 KeyError。

【推导过程】

python
d = {"a": 1}
d.get("b")   # 键 "b" 不存在,返回默认值 None
d["b"]       # 键 "b" 不存在,抛出 KeyError

【逐项辨析】 D. None 和抛 KeyError:正确。get() 找不到键时返回默认值 None;下标访问找不到键时抛出 KeyError。 B. 都抛 KeyError:错误。get() 方法在键不存在时不会抛异常。 C. 都是 None:错误。下标访问 d["b"] 会抛出 KeyError,不会返回 None。 A. None 和 None:错误。下标访问会抛异常,不会返回 None。

【知识点】 dict.get(key, default=None) 是安全取值的首选方式:键存在时返回对应值;键不存在时返回 default(默认为 None);不会修改原字典。

d[key] 是直接访问:键存在时返回对应值;键不存在时抛出 KeyError,程序可能因此中断。

在需要区分“键不存在”和“值为 None”的场景,可使用 key in d 先判断成员关系,或使用 collections.defaultdict 实现自动填充默认值。

【记忆锚点】 “中括号硬取会报错,get 方法温柔有默认值。”

【易混对比】

方式键不存在时是否抛异常可设默认值是否修改字典
d[k]抛 KeyError是否否
d.get(k)返回 None否是(第二参数)否
d.setdefault(k, v)插入 k:v 并返回 v否是是

换问法:d.get("b", 0) 的结果是什么?答:0,因为指定了默认值参数。

【自测】

python
d = {"a": None}
print(d.get("a", "default"))
print(d.get("b", "default"))

答:None 和 "default"。注意 get 的默认值只在键不存在时生效,键存在但值为 None 仍返回 None。与第 P26 题连考。

【知识关联】

  • 同库关联:与 P28(删除)、P23;get 默认值 vs KeyError。
  • 实现层:d[k] 缺失抛 KeyError;get(k,default) 返回默认。
  • 面试追问:① 如何安全取值?② setdefault 用途?

【拓展延伸】

  • 变式问法:d.get("x", []) 别名坑;collections.defaultdict。
  • 版本差异:Py3.9 d | other 合并。
  • 工程注意点:计数用 defaultdict/Counter;嵌套取值可用结构化解析。

P26 · 知识点:字典遍历 ​

【题目】for k in d: 遍历的是字典的?

A. 索引 B. 值 C. 键值对 D. 键

答案:D

【考点】字典遍历方式:默认键、values() 值、items() 键值对。

【结论】选 D。for k in d 默认遍历字典的键,等价于 for k in d.keys()。

【逐项辨析】 D. 键:正确。for k in d 等价于 for k in d.keys(),遍历所有键。 B. 值:错误。遍历值需显式使用 d.values()。 C. 键值对:错误。遍历键值对需使用 d.items(),每次迭代得到 (key, value) 元组。 A. 索引:错误。字典是映射类型,不存在 list 那样的整数索引概念。

【知识点】 Python 字典提供三种标准遍历方式:

  1. for k in d:遍历键,可简写,返回 dict_keys 视图对象。
  2. for v in d.values():遍历值,返回 dict_values 视图对象。
  3. for k, v in d.items():遍历键值对,返回 dict_items 视图对象,支持元组解包。

Python 3.7+ 中字典保持插入顺序,但无整数索引。若需要按序号处理,应使用 enumerate(d) 获取序号与键的配对,或先转为 list。

视图对象(view object)与列表的区别:视图是原字典的动态映射,原字典修改后视图会反映变化,但视图本身不支持索引。

【记忆锚点】 “直接遍历是键,values 是值,items 成对出。”

【易混对比】

遍历方式写法每次迭代得到返回类型
键for k in d键dict_keys
值for v in d.values()值dict_values
键值对for k, v in d.items()(键, 值) 元组dict_items

换问法:for i, k in enumerate(d): 中 i 和 k 分别代表什么?答:i 是枚举序号(从 0 开始),k 是字典的键。

【自测】

python
d = {"x": 1, "y": 2}
print(list(d))
print(list(d.values()))

答:['x', 'y'] 和 [1, 2]。与第 P27 题连考。

【知识关联】

  • 同库关联:与 P23 有序性;items/keys/values 视图。
  • 实现层:Py3 返回动态视图,修改字典时迭代会 RuntimeError。
  • 面试追问:① 遍历中删除怎么办?② items 与 list(items)?

【拓展延伸】

  • 变式问法:for k in d 与 for k in d.keys();按值排序遍历。
  • 版本差异:Py3 视图 vs Py2 列表拷贝。
  • 工程注意点:边遍历边改先 list(d.items())。

P27 · 知识点:字典更新 ​

【题目】d = {"a": 1}; d.update({"a": 2, "b": 3}); 执行后 d 是?

A. 抛异常 B. {'a': 1, 'b': 3} C. {'a': 2} D.

答案:D

【考点】update() 合并字典:已有键覆盖,新键添加。

【结论】选 D。update() 原地更新字典,已有键 "a" 被覆盖为 2,新键 "b" 被添加为 3。

【推导过程】

python
d = {"a": 1}
d.update({"a": 2, "b": 3})
# 键 "a" 已存在,值由 1 覆盖为 2
# 键 "b" 不存在,新增 "b": 3
# d 变为 {"a": 2, "b": 3}

【逐项辨析】 D. {'a': 2, 'b': 3}:正确。"a" 被覆盖为 2,"b" 被新增为 3。 B. {'a': 1, 'b': 3}:错误。update 会覆盖已有键的值,"a" 不会保持原值。 C. {'a': 2}:错误。update 不会删除未涉及的键,且会添加新键 "b"。 A. 抛异常:错误。update 传入字典是合法操作,不会抛异常。

【知识点】 dict.update([other]) 的行为:接收字典或键值对可迭代对象;对已有键用新值覆盖旧值;对不存在键添加新键值对;操作是原地修改,返回值为 None。

现代 Python 提供更多合并方式:

  • Python 3.9+ 支持合并运算符:d | other 返回新字典,d |= other 原地更新。
  • Python 3.5+ 支持解包合并:{**d1, **d2} 返回新字典。

注意区分返回新对象与原地修改:update() 和 |= 是原地操作,| 和 {**d1, **d2} 创建新对象。

【记忆锚点】 “update 更新有两条:旧键覆盖新键招,返回 None 别搞错。”

【易混对比】

方式是否原地修改返回值适用版本
d.update(d2)是None通用
d | d2否新字典Python 3.9+
d |= d2是NonePython 3.9+
否新字典Python 3.5+

换问法:d = {"a": 1}; d.update(a=2); print(d) 输出什么?答:{'a': 2},关键字参数形式同样会覆盖已有键。

【自测】

python
d1 = {"a": 1}
d2 = d1
d1.update({"b": 2})
print(d2 is d1)

答:True。update 是原地修改,d2 仍引用同一对象,is 判断为真。与第 P28 题连考。

【知识关联】

  • 同库关联:与 P25/P28;update 合并。
  • 实现层:update 就地合并;| 合并出新字典(3.9+)。
  • 面试追问:① 同 key 谁覆盖谁?② 与 setdefault?

【拓展延伸】

  • 变式问法:d.update(e=1);{**a,**b}。
  • 版本差异:3.9 合并运算符。
  • 工程注意点:配置合并注意优先级;浅合并嵌套要递归。

P28 · 知识点:字典删除 ​

【题目】d = {"a": 1, "b": 2}; d.pop("a") 的返回值是?执行后 d 是?

A. None 和 {'b': 2} B. 抛异常 C. 1 和 {'a': 1, 'b': 2} D. 1 和

答案:D

【考点】pop(key) 删除并返回值;del 删除不返回;popitem() 删除末尾项。

【结论】选 D。pop("a") 删除键 "a" 并返回其值 1,执行后 d 仅保留 {'b': 2}。

【推导过程】

python
d = {"a": 1, "b": 2}
d.pop("a")   # 删除键 "a",返回对应的值 1
# d 变为 {"b": 2}

【逐项辨析】 D. 1 和 {'b': 2}:正确。pop("a") 返回被删除的值 1,原字典删除该键值对。 B. 抛异常:错误。键 "a" 存在于字典中,pop 不会抛异常。 C. 1 和 {'a': 1, 'b': 2}:错误。pop 会真正删除键值对,不会保留 "a"。 A. None 和 {'b': 2}:错误。pop 返回的是被删除键对应的值 1,不是 None。

【知识点】 字典删除的三种主要方式:

  1. pop(key[, default]):删除指定键并返回其值;键不存在时返回 default,未提供 default 则抛 KeyError。
  2. del d[key]:删除指定键值对,不返回值;键不存在抛 KeyError。
  3. popitem():删除并返回最后插入的键值对(LIFO 顺序,Python 3.7+),字典为空时抛 KeyError。

clear() 可清空整个字典,使其变为空字典 {}。

注意 Python 3.7+ 中字典保持插入顺序,popitem() 按后进先出(LIFO)移除。早期版本(3.6 及以前)中 popitem() 移除顺序是任意的。

【记忆锚点】 “pop 有返回值,del 只管删,popitem 弹末尾,clear 全清空。”

【易混对比】

方法是否返回值删除对象键不存在时
pop(key)是(值)指定键抛 KeyError
pop(key, default)是(值或 default)指定键返回 default
del d[key]否指定键抛 KeyError
popitem()是(键值对元组)最后插入项抛 KeyError
clear()None全部元素无

换问法:d.pop("c", 0) 的结果是什么?答:0,因为键 "c" 不存在且提供了默认值参数。

【自测】

python
d = {"a": 1, "b": 2}
print(d.popitem())
print(d)

答:('b', 2) 和 {'a': 1}(Python 3.7+ 按 LIFO 顺序弹出最后插入项)。与第 P29 题连考。

【知识关联】

  • 同库关联:与 P25;pop/del/popitem。
  • 实现层:pop 可给默认;del 缺失 KeyError;popitem 弹出(3.7+ 后进先出)。
  • 面试追问:① 清空字典?② pop 与 del 选择?

【拓展延伸】

  • 变式问法:d.pop(k, None);d.clear()。
  • 版本差异:popitem 语义 Py3.7 明确 LIFO。
  • 工程注意点:清理缓存条目用 pop;不要遍历中 del 原字典。

P29 · 知识点:集合特性 ​

【题目】关于集合(set)的说法,正确的是?

A. 集合是有序的 B. 集合允许重复元素 C. 集合中的元素必须可哈希(不可变) D. 集合支持下标索引访问

答案:C

【考点】集合三大特性:无序、唯一、元素可哈希。

【结论】选 C。集合中的元素必须是不可变的可哈希对象。

【逐项辨析】 A. 集合是有序的:错误。集合是无序容器,不保证元素顺序,也不支持索引访问。 B. 集合允许重复元素:错误。集合具有唯一性,重复元素会被自动去重。 C. 集合中的元素必须可哈希(不可变):正确。与字典键的要求一致,元素必须是不可变类型。 D. 集合支持下标索引访问:错误。集合无序,不支持索引、切片等序列操作。

【知识点】 集合(set)的三大核心特性:

  1. 无序性:元素没有固定顺序,不支持索引访问和切片操作。
  2. 唯一性:自动去重,重复元素只保留一个。
  3. 元素可哈希:所有元素必须是不可变类型(如数字、字符串、元组),列表和字典不能作为集合元素。

集合底层基于哈希表实现,因此成员检测(x in s)的时间复杂度为 O(1),效率远高于列表的 O(n)。frozenset 是不可变集合,本身可哈希,可作为字典键或其他集合的元素。

【记忆锚点】 “集合三特性:无序、唯一、要哈希。”

【易混对比】

特性列表 list集合 set元组 tuple
有序是否是
可重复是否是
可变是是否
可哈希否否是(仅当元素都可哈希时;含列表即不可哈希,hash((1, [2])) 实测抛 TypeError: unhashable type: 'list',与 P24、P11 的口径一致)
支持索引是否是
成员检测复杂度O(n)O(1)O(n)

换问法:{1, 1, 2, 2, 3} 的结果是什么?答:{1, 2, 3},重复元素被自动去重。

【自测】

python
s = {1, 2, 3}
s.add(3)
print(len(s))

答:3。添加重复元素 3 不会改变集合大小,集合自动去重。与第 P30 题连考。

【知识关联】

  • 同库关联:与 P30/P31/P32、J37(HashSet)。
  • 实现层:set 基于哈希,无序(实现可能碰巧有序但不可依赖)、自动去重。
  • 面试追问:① set 与 frozenset?② 如何保留插入序?

【拓展延伸】

  • 变式问法:set([1,1,2]);空 set 必须 set() 不能 {}。
  • 版本差异:语义稳定。
  • 工程注意点:去重+成员判断用 set;需要序用 dict.fromkeys 或 sorted。

P30 · 知识点:集合运算 ​

【题目】 & {2, 3, 4} 的结果是?

A. {2, 3, 4} B. {1, 2, 3, 4} C. {1, 4} D.

答案:D

【考点】集合运算符号:& 交集、| 并集、- 差集、^ 对称差。

【结论】选 D。& 运算符表示交集,返回两集合共有的元素 {2, 3}。

【推导过程】

python
{1, 2, 3} & {2, 3, 4}
# & 为交集运算符,保留两集合共有元素
# 共有元素:2, 3
# 结果:{2, 3}

【逐项辨析】 D. {2, 3}:正确。两集合共有的元素是 2 和 3。 B. {1, 2, 3, 4}:错误。这是并集运算符 | 的结果。 C. {1, 4}:错误。这是对称差集运算符 ^ 的结果。 A. {2, 3, 4}:错误。无对应标准集合运算会产生此结果。

【知识点】 Python 集合的四种基本运算:

  1. 交集 & / intersection():两集合共有元素。
  2. 并集 | / union():两集合所有元素(自动去重)。
  3. 差集 - / difference():在左集合但不在右集合的元素。
  4. 对称差集 ^ / symmetric_difference():仅在其中一个集合中的元素(并集减去交集)。

运算符支持复合赋值形式:s |= other 等价于 s.update(other),s &= other 等价于 s.intersection_update(other) 等。

方法形式的运算符可以接受任意可迭代对象作为参数,而运算符形式要求右侧必须是 set 类型。

【记忆锚点】 “& 交 | 并 - 差去,^ 对称各一半。”

【易混对比】

运算符方法含义示例结果
&intersection交集{1,2,3} & {2,3,4} =
|union并集{1,2,3} | {2,3,4} =
-difference差集{1,2,3} - {2,3,4} =
^symmetric_difference对称差{1,2,3} ^ {2,3,4} =

换问法:{1, 2, 3} - {2, 3, 4} 的结果是什么?答:{1},差集保留左侧集合独有的元素。

【自测】

python
a = {1, 2, 3}
b = {2, 3, 4}
print(a ^ b)

答:{1, 4}。与第 P31 题连考。

【知识关联】

  • 同库关联:与 P29;并交差对称差运算符 | & - ^。
  • 实现层:集合运算 C 实现高效;也可用方法 form。
  • 面试追问:① 可变与不可变集合运算?② 子集判断?

【拓展延伸】

  • 变式问法:{1,2} & {2,3};issubset。
  • 版本差异:语义稳定。
  • 工程注意点:标签过滤用交集;权限集合运算清晰。

P31 · 知识点:集合去重 ​

【题目】list(set([1, 2, 2, 3, 3, 3])) 的结果是?

A. {1, 2, 3} B. [1, 2, 2, 3, 3, 3] C. 抛异常 D. [1, 2, 3]

答案:D

【考点】用 set 去重后转回列表。

【结论】选 D。利用集合自动去重后转回列表,得到 [1, 2, 3]。

【推导过程】

python
[1, 2, 2, 3, 3, 3]       # 原始列表
set([1, 2, 2, 3, 3, 3])   # 转为集合去重 → {1, 2, 3}
list({1, 2, 3})           # 转回列表 → [1, 2, 3]

【逐项辨析】 D. [1, 2, 3]:正确。先转 set 去重,再转 list 恢复列表类型。 B. [1, 2, 2, 3, 3, 3]:错误。set() 会去除所有重复元素。 C. 抛异常:错误。列表元素均为整数(可哈希),可正常创建集合。 A. {1, 2, 3}:错误。最外层调用了 list(),结果已转回列表,不是集合。

【知识点】 集合去重是 Python 中最简洁的去重方式之一:

  1. set(可迭代对象):利用哈希表去重,时间复杂度 O(n)。
  2. 转回 list:list(set(...)) 恢复列表类型。

关键注意事项:由于集合无序,去重后元素顺序不保证与原始顺序一致。对整数小范围场景通常恰好有序,但程序不应依赖该顺序。

若需保序去重,Python 3.7+ 推荐使用 dict.fromkeys():list(dict.fromkeys([1, 2, 2, 3])),既保持首次出现顺序,又具有 O(n) 时间复杂度。

【记忆锚点】 “去重两步走:先 set 再 list,顺序不保要留神。”

【易混对比】

去重方式代码是否保序时间复杂度
set 转 listlist(set(lst))否O(n)
dict.fromkeyslist(dict.fromkeys(lst))是(3.7+)O(n)
遍历+判断循环 + if x not in res是O(n²)

换问法:list(set([3, 1, 2])) 的结果一定是 [1, 2, 3] 吗?答:不一定,集合无序,任何顺序都可能出现,程序不应依赖顺序。

【自测】

python
lst = [1, 1, 2, 2, 3, 3]
print(list(dict.fromkeys(lst)))

答:[1, 2, 3]。dict.fromkeys() 是保序去重的优雅写法,Python 3.7+ 有效。与第 P32 题连考。

【知识关联】

  • 同库关联:与 P29;list(set(L)) 不保序。
  • 实现层:哈希去重;dict.fromkeys 可保序去重(3.7+)。
  • 面试追问:① 如何去重且保序?② 不可哈希元素?

【拓展延伸】

  • 变式问法:列表含 dict 去重要用别的方式(json 化或 key 函数)。
  • 版本差异:dict 有序后 fromkeys 成为常用保序去重。
  • 工程注意点:大数据去重 set;展示顺序注意。

P32 · 知识点:frozenset ​

【题目】frozenset 与 set 的区别是?

A. frozenset 可变 B. frozenset 是有序的 C. 两者没有任何区别 D. frozenset 不可变(可哈希),因此可以作为字典的键

答案:D

【考点】不可变集合 frozenset 的用途。

【结论】选 D。frozenset 是不可变集合,可哈希,因此能作为字典的键或集合的元素。

【逐项辨析】 A. frozenset 可变:错误。frozenset 是不可变的,创建后无法修改。 D. frozenset 不可变(可哈希),因此可以作为字典的键:正确。不可变性带来可哈希性,这是其核心价值。 C. 两者没有任何区别:错误。可变性是 set 与 frozenset 的本质区别。 B. frozenset 是有序的:错误。frozenset 与 set 一样都是无序容器。

【知识点】 frozenset 与 set 的核心区别:

  1. 可变性:set 可变,支持 add、remove、discard 等修改操作;frozenset 不可变,创建后内容固定。
  2. 可哈希性:frozenset 可哈希,set 不可哈希。
  3. 用途差异:frozenset 可作为字典键、其他集合的元素;set 因不可哈希,既不能作字典键,也不能嵌套进另一个 set。

两者共同点:均无序、元素唯一、元素必须可哈希,底层均为哈希表实现,成员检测复杂度 O(1)。

【记忆锚点】 “frozen 冻住不能改,哈希合格当键来。”

【易混对比】

特性setfrozenset
可变是否
可哈希否是
支持 add / remove是否
可作字典键否是
可作集合元素否是
无序 / 唯一是是

换问法:s = frozenset([1, 2]); d = {s: "value"} 是否合法?答:合法,frozenset 可哈希,可作为字典键。

【自测】

python
s1 = {1, 2}
s2 = frozenset([1, 2])
print(hash(s2))
# print(hash(s1))  # 这行会怎样?

答:输出 s2 的哈希值;hash(s1) 会抛出 TypeError: unhashable type: 'set',因为 set 不可哈希。与第 P23 题连考。

【知识关联】

  • 同库关联:与 P29/P24;不可变集合作为 dict key 或放入 set。
  • 实现层:frozenset 可哈希。
  • 面试追问:① 何时用 frozenset?② 与 tuple 表示集合的差异?

【拓展延伸】

  • 变式问法:{frozenset({1,2}): "x"}。
  • 版本差异:语义稳定。
  • 工程注意点:权限位/标签组需要哈希时用 frozenset。

持续学习,持续积累。