返回博客

12. dict 与 set:字典与集合

12. dict 与 set:字典与集合

第十二篇:dict 与 set——字典与集合完全指南

前言

**字典(dict)和集合(set)**是 Python 中两种强大的关联数据结构。字典通过键值对实现 O(1) 的查找效率,集合用于高效去重和数学集合运算。本文全面讲解它们的创建、增删改查、遍历方法以及性能特点。

字典(dict)基础

创建方式

# 字面量创建
empty = {}
student = {"name": "小明", "age": 25, "score": 92}

# 用 dict() 构造函数
pairs = [("name", "小明"), ("age", 25)]
from_pairs = dict(pairs)

# 关键字参数创建(键必须是字符串)
user = dict(name="小红", age=22, city="北京")

len() 函数

user = {"name": "小明", "age": 25, "city": "北京"}
print(len(user))  # 3 — 键值对数量

dict 的基本操作

索引访问与安全获取

student = {"name": "小明", "age": 25, "score": 92}

# ❌ 直接访问:键不存在则 KeyError
# print(student["grade"])  # KeyError!

# ✅ get() 安全访问,支持默认值
print(student.get("name"))       # 小明
print(student.get("grade"))      # None
print(student.get("grade", "N/A"))  # N/A

添加和修改

student = {"name": "小明", "age": 25}

# 直接赋值(新键则添加,已有键则修改)
student["grade"] = "三年级"
student["age"] = 26

# update() 批量更新
student.update({"score": 95, "city": "北京"})
print(student)  # {..., "score": 95, "city": "北京"}

删除元素

# pop() — 按键删除并返回值
age = student.pop("age")
print(age)          # 25
print(student)      # 不含 age 键

# pop() 设置默认值(防止 KeyError)
missing = student.pop("grade", "未知")
print(missing)      # 未知

# popitem() — 弹出最后一个键值对
last = student.popitem()

# del 删除指定键
del student["name"]

# clear() 清空整个字典
student.clear()

常用方法速查

student = {"name": "小明", "age": 25, "score": 92}

# keys()/values()/items()
for key in student.keys():    pass
for value in student.values(): pass
for key, value in student.items(): print(f"{key}: {value}")

# setdefault() — 键存在返回值,否则添加默认值
result = student.setdefault("grade", "一年级")

# copy() 浅拷贝
copy_student = student.copy()

成员检查

print("name" in student)       # True — 检查的是键
print("小明" in student.values())  # True — 需要遍历

字典推导式

# 基本形式:{键表达式: 值表达式 for ...}
squares = {x: x ** 2 for x in range(1, 6)}
print(squares)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 带过滤条件
evens = {x: x ** 2 for x in range(1, 11) if x % 2 == 0}
print(evens)  # {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}

# 从现有字典推导
upper_names = {k.upper(): v for k, v in student.items()}

# 嵌套字典
matrix = {(i, j): i * j for i in range(1, 4) for j in range(1, 4)}

集合(set)基础

创建方式

# ⚠️ 空集合必须用 set()!{} 是空字典
empty = set()

# 创建含元素的集合
colors = {"red", "green", "blue"}

# 从列表创建(自动去重)
duplicates = [1, 2, 2, 3, 3, 3, 4]
unique = set(duplicates)
print(unique)  # {1, 2, 3, 4}

len() 函数

print(len(colors))  # 元素个数

集合的基本操作

添加和删除

colors = {"红", "绿", "蓝"}

# add() — 添加单个元素(不重复)
colors.add("黄")
colors.add("红")  # 无变化

# update() — 批量添加
colors.update(["白", "黑", "灰"])

# remove() — 删除(不存在抛 KeyError)
colors.remove("红")

# discard() — 删除(不存在也不报错)
colors.discard("橙")

# pop() — 删除并返回任意元素
removed = colors.pop()

# clear() 清空
colors.clear()

frozenset 不可变集合

# frozenset 不可变,可以作为字典键或嵌套集合的元素
fs = frozenset([1, 2, 3])
# fs.add(4)  # AttributeError!

# 用法:作为字典的键
data = {frozenset(["a", "b"]): 1, frozenset(["c", "d"]): 2}
print(data[frozenset(["a", "b"])])  # 1

集合的数学运算

交并差集速查

操作 运算符 方法 含义
交集 & .intersection() 共同元素
并集 | .union() 所有元素(去重)
差集 - .difference() 在 A 但不在 B
对称差 ^ .symmetric_difference() 只在一个集合中
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}

print(a & b)              # {4, 5} — 交集
print(a | b)              # {1, 2, 3, 4, 5, 6, 7, 8} — 并集
print(a - b)              # {1, 2, 3} — 差集
print(a ^ b)              # {1, 2, 3, 6, 7, 8} — 对称差

子集和超集

base = {1, 2, 3, 4, 5}
subset = {1, 2, 3}
superset = {1, 2, 3, 4, 5, 6}

print(subset.issubset(base))    # True
print(base.issuperset(subset))  # True
print(subset < base)            # True — 真子集
print(base > subset)            # True — 真超集

# 不相交检查
a = {1, 2, 3}
b = {4, 5, 6}
print(a.isdisjoint(b))   # True — 没有共同元素

集合推导式

# 基本形式
squares = {x ** 2 for x in range(1, 6)}
print(squares)  # {1, 4, 9, 16, 25}

# 过滤条件 + 去重
vowels = {"a", "e", "i", "o", "u"}
words = ["apple", "banana", "cherry"]
word_vowels = {char for word in words for char in word if char in vowels}
print(word_vowels)  # {'a', 'e'} — 自动去重

dict vs set 对比总结

特性 dict set
存储单位 键值对 单一元素
语法 {"key": "val"} {"elem"}
可变性 元素可变 元素可变
哈希要求 键必须可哈希 元素必须可哈希
用途 快速查找映射 去重、集合运算

何时用哪个?

# ✅ 用 dict:数据之间存在映射关系
user_info = {"name": "小明", "age": 25}
counter = {"click": 100, "view": 500}
lookup = {str(i): f"数字{i}" for i in range(10)}

# ✅ 用 set:需要去重或集合运算
seen_pages = set()
allowed_tags = {"python", "web", "ai"}
common_users = users_a & users_b  # 求交集

实战示例

词频统计

def count_words(text):
    words = text.lower().split()
    counter = {}
    for word in words:
        clean = word.strip(".,!?;:'()-")
        if clean:
            counter[clean] = counter.get(clean, 0) + 1
    return counter

text = "Python is great. Python is fun. Is Python the best?"
freq = count_words(text)
print(freq)
# {'python': 3, 'is': 2, 'great': 1, 'fun': 1, 'the': 1, 'best': 1}

嵌套字典成绩管理

students = {
    "张三": {"math": 95, "english": 88},
    "李四": {"math": 72, "english": 91},
}
print(students["张三"]["math"])  # 95

subjects = ["math", "english"]
for subject in subjects:
    total = sum(s[subject] for s in students.values())
    avg = total / len(students)
    print(f"{subject} 平均分:{avg:.1f}")

defaultdict 简化代码

from collections import defaultdict

# 普通字典遇到不存在键会报错
# groups = {}
# groups[item[0]].append(item)  # KeyError!

# defaultdict 自动创建默认值
groups = defaultdict(list)
for item in ["apple", "apricot", "banana", "blueberry"]:
    groups[item[0]].append(item)
print(dict(groups))
# {'a': ['apple', 'apricot'], 'b': ['banana', 'blueberry']}

双重循环找重复项

def find_duplicates(items):
    seen = set()
    duplicates = set()
    for item in items:
        if item in seen:
            duplicates.add(item)
        else:
            seen.add(item)
    return duplicates

print(find_duplicates([1, 2, 3, 2, 4, 1, 5, 3]))  # {1, 2, 3}

性能特点

为什么 dict/set 这么快?

Python 的 dict 和 set 底层基于哈希表(Hash Table):

import timeit

large_dict = {i: f"value_{i}" for i in range(1_000_000)}
start = timeit.default_timer()
_ = large_dict[999999]  # 瞬间完成
print("dict 查找耗时:毫秒级")

large_list = list(range(1_000_000))
start = timeit.default_timer()
_ = 999999 in large_list  # 线性时间
print("list 查找耗时:随规模增长")

哈希约束

# ✅ 可哈希(不可变类型)
hashable_items = {1, "hello", (1, 2), 3.14, True, None}
my_dict = {1: "one", "hello": "world", (1, 2): "tuple_key"}

# ❌ 不可哈希(不能作为 dict 的键或 set 的元素)
# unhashable = {[1, 2]}       # TypeError
# bad_dict = {[1, 2]: "value"}  # TypeError

总结

本文涵盖了 Python dict 和 set 的核心知识:

  1. dict 基础 — 三种创建方式、len()
  2. 增删改查 — 直接赋值、update()/pop()/del()/get()/setdefault()/clear()
  3. 遍历方法 — keys()/values()/items()
  4. 成员检查 — in/not in 只检查键
  5. 字典推导式 — 简洁高效的创建方式
  6. set 基础 — 创建(注意 set() ≠ {})、add()/remove()/discard()/pop()/clear()
  7. frozenset — 不可变集合,可作为字典键
  8. 数学运算 — 交(&)、并(|)、差(-)、对称差(^)、子集/超集、不相交
  9. 集合推导式 — 自动去重
  10. 性能 — 哈希表 O(1) 查找 vs list O(n)
  11. 实用技巧 — defaultdict、嵌套字典、找重复项

下一篇文章将深入讲解类与实例:面向对象编程基础。


本文是 Python 教程系列的第十二篇。