目录

Python 字典与集合

学习目标

  • 掌握字典的创建、访问、增删改查操作
  • 理解集合的特性和数学运算
  • 学会字典推导式和集合推导式
  • 了解哈希表的基本原理

一、字典(dict)

字典是 Python 中用于存储键值对的数据结构,它是无序的(Python 3.7+ 实际保持插入顺序)、键唯一的映射类型。

1.1 创建字典

# 直接创建
user = {"name": "Alice", "age": 25, "city": "Beijing"}

# 使用 dict() 构造函数
user2 = dict(name="Bob", age=30, city="Shanghai")

# 从键值对序列创建
user3 = dict([("name", "Charlie"), ("age", 35)])

# 空字典
empty = {}
empty2 = dict()

# 使用 fromkeys() 创建带默认值的字典
keys = ["a", "b", "c"]
d = dict.fromkeys(keys, 0)
print(d)   # {'a': 0, 'b': 0, 'c': 0}

1.2 访问和修改

user = {"name": "Alice", "age": 25, "city": "Beijing"}

# 访问
print(user["name"])        # Alice
# print(user["gender"])    # KeyError!

# 安全访问
print(user.get("gender"))           # None
print(user.get("gender", "未知"))   # 未知(默认值)

# 修改和添加
user["age"] = 26           # 修改已有键
user["gender"] = "female"  # 添加新键
print(user)

# 批量更新
user.update({"phone": "123456", "email": "alice@example.com"})
print(user)

# 使用 setdefault:键不存在时设置默认值
user.setdefault("country", "China")
print(user["country"])     # China
user.setdefault("country", "USA")   # 已存在,不修改
print(user["country"])     # China

1.3 删除操作

user = {"name": "Alice", "age": 25, "city": "Beijing"}

# 删除指定键
del user["city"]
print(user)                # {'name': 'Alice', 'age': 25}

# pop() 删除并返回值
age = user.pop("age")
print(age, user)           # 25 {'name': 'Alice'}

# popitem() 删除并返回最后一个键值对(Python 3.7+ 按插入顺序)
last = user.popitem()
print(last)                # ('name', 'Alice')

# clear() 清空
user.clear()
print(user)                # {}

1.4 遍历字典

user = {"name": "Alice", "age": 25, "city": "Beijing"}

# 遍历键
for key in user:
    print(key)

# 遍历值
for value in user.values():
    print(value)

# 遍历键值对
for key, value in user.items():
    print(f"{key}: {value}")

# 检查键是否存在
print("name" in user)      # True
print("gender" in user)    # False

二、字典的高级用法

2.1 嵌套字典

school = {
    "class_a": {
        "teacher": "Mr. Wang",
        "students": ["Alice", "Bob"]
    },
    "class_b": {
        "teacher": "Ms. Li",
        "students": ["Charlie", "David"]
    }
}

print(school["class_a"]["teacher"])       # Mr. Wang
print(school["class_b"]["students"][0])   # Charlie

2.2 字典合并(Python 3.9+)

d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}

# | 合并(3.9+)
merged = d1 | d2
print(merged)              # {'a': 1, 'b': 3, 'c': 4}

# |= 就地合并
d1 |= d2
print(d1)                  # {'a': 1, 'b': 3, 'c': 4}

2.3 字典排序

scores = {"Alice": 85, "Bob": 92, "Charlie": 78}

# 按键排序
sorted_by_key = dict(sorted(scores.items()))
print(sorted_by_key)       # {'Alice': 85, 'Bob': 92, 'Charlie': 78}

# 按值排序
sorted_by_value = dict(sorted(scores.items(), key=lambda x: x[1], reverse=True))
print(sorted_by_value)     # {'Bob': 92, 'Alice': 85, 'Charlie': 78}

三、集合(set)

集合是一个无序、不重复的元素集合,支持数学上的集合运算。

3.1 创建集合

# 直接创建
s = {1, 2, 3, 3, 3}        # 重复自动去重
print(s)                   # {1, 2, 3}

# 使用 set() 构造函数
s2 = set([1, 2, 3, 3, 3])  # 从列表创建
print(s2)                  # {1, 2, 3}

# 空集合(注意:{} 是空字典!)
empty_set = set()
print(type(empty_set))     # <class 'set'>

3.2 集合操作

s = {1, 2, 3}

# 添加元素
s.add(4)
print(s)                   # {1, 2, 3, 4}

# 批量添加
s.update([5, 6])
print(s)                   # {1, 2, 3, 4, 5, 6}

# 删除元素
s.remove(6)                # 元素不存在会报错
s.discard(100)             # 元素不存在不报错
popped = s.pop()           # 随机删除并返回一个元素
print(s)

s.clear()                  # 清空

3.3 集合运算

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# 并集
print(a | b)               # {1, 2, 3, 4, 5, 6}
print(a.union(b))

# 交集
print(a & b)               # {3, 4}
print(a.intersection(b))

# 差集
print(a - b)               # {1, 2}
print(a.difference(b))

# 对称差集(只在其中一个集合中的元素)
print(a ^ b)               # {1, 2, 5, 6}
print(a.symmetric_difference(b))

# 子集和超集
print({1, 2} < a)          # True(真子集)
print({1, 2, 3} <= a)      # True(子集)
print(a > {1, 2})          # True(真超集)

3.4 不可变集合 frozenset

# frozenset 不可变,可作为字典的键
fs = frozenset([1, 2, 3])
# fs.add(4)                # AttributeError!

# 可用作字典键
mapping = {frozenset([1, 2]): "A", frozenset([3, 4]): "B"}
print(mapping[frozenset([1, 2])])   # A

四、推导式

4.1 字典推导式

# 基本字典推导式
squares = {x: x**2 for x in range(6)}
print(squares)             # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

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

# 交换键值
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
print(swapped)             # {1: 'a', 2: 'b', 3: 'c'}

# 从两个列表创建字典
keys = ["a", "b", "c"]
values = [1, 2, 3]
d = {k: v for k, v in zip(keys, values)}
print(d)                   # {'a': 1, 'b': 2, 'c': 3}

4.2 集合推导式

# 基本集合推导式
s = {x**2 for x in range(10)}
print(s)                   # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

# 带条件
evens = {x for x in range(20) if x % 2 == 0}
print(evens)               # {0, 2, 4, 6, 8, 10, 12, 14, 16, 18}

# 去重(从列表提取不重复元素)
items = [1, 2, 2, 3, 3, 3, 4]
unique = {x for x in items}
print(unique)              # {1, 2, 3, 4}

五、哈希原理简述

字典和集合的键必须是**可哈希(hashable)**的对象。可哈希对象的特点:

  • 不可变(immutable)
  • 有固定的哈希值(通过 hash() 函数计算)
# 可哈希的对象(可做字典键)
print(hash("hello"))       # 字符串可哈希
print(hash(42))            # 整数可哈希
print(hash((1, 2, 3)))     # 元组可哈希

# 不可哈希的对象(不能做字典键)
# hash([1, 2, 3])          # TypeError: 列表不可哈希
# hash({"a": 1})           # TypeError: 字典不可哈希

# 检查是否可哈希
from collections.abc import Hashable
print(isinstance("hello", Hashable))   # True
print(isinstance([1, 2], Hashable))    # False

六、综合示例

"""
词频统计程序
"""

text = """
Python is great and Python is easy.
Learning Python is fun and Python is powerful.
"""

# 清洗并分词
words = text.lower().replace(".", "").replace(",", "").split()

# 统计词频
frequency = {}
for word in words:
    frequency[word] = frequency.get(word, 0) + 1

# 使用字典推导式
# frequency = {word: words.count(word) for word in set(words)}

print("词频统计:")
print("-" * 30)
for word, count in sorted(frequency.items(), key=lambda x: x[1], reverse=True):
    print(f"{word:<12} {count:>3} 次")

# 找出只出现一次的单词
unique_words = {word for word, count in frequency.items() if count == 1}
print(f"\n只出现一次的单词: {unique_words}")

# 找出最常见的词
most_common = max(frequency.items(), key=lambda x: x[1])
print(f"最常见的词: '{most_common[0]}' 出现了 {most_common[1]} 次")

小结

  • 字典存储键值对,键必须可哈希且唯一,值可以是任意类型
  • get()setdefault()update() 是字典的常用方法
  • 集合无序不重复,支持并集、交集、差集等数学运算
  • 字典推导式和集合推导式语法与列表推导式类似
  • frozenset 是不可变集合,可作为字典键
  • 可哈希对象必须是不可变的(字符串、数字、元组等)

练习

  1. 有一个字符串 "hello world hello python",统计每个单词出现的次数。
  2. 两个列表 a = [1, 2, 3, 4, 5]b = [4, 5, 6, 7, 8],找出它们的共同元素和各自独有的元素。
  3. 编写程序,删除字典中值为 None 或空字符串的键值对。
  4. 使用集合推导式从一段文本中提取所有不重复的字母(忽略大小写和标点)。
  5. 有一个嵌套字典表示的菜单,编写函数按价格从低到高打印所有菜品。