Python集合与冻结集合高级
Python集合与冻结集合高级
==============================
一、frozenset作为字典键
frozenset是不可变的哈希集合,可以作为字典的键或集合的元素,
而普通set则不行。
# frozenset作为字典键
路由表 = {
frozenset({"北京", "上海"}): "京沪线",
frozenset({"广州", "深圳"}): "广深线",
frozenset({"成都", "重庆"}): "成渝线",
}
def 查询路线(城市1: str, 城市2: str) -> str:
"""根据两个城市查询路线名称"""
路线键 = frozenset({城市1, 城市2})
return 路由表.get(路线键, "未知路线")
print(f"路线: {查询路线('北京', '上海')}")
print(f"路线: {查询路线('上海', '北京')}") # 顺序无关
# frozenset作为集合的元素
用户权限组 = {
frozenset({"读取", "写入"}), # 普通用户
frozenset({"读取", "写入", "删除"}), # 管理员
frozenset({"读取"}), # 只读用户
}
print(f"权限组数量: {len(用户权限组)}")
# 检查权限组合是否存在
def 检查权限组合(*权限):
return frozenset(权限) in 用户权限组
print(f"读写权限存在: {检查权限组合('读取', '写入')}")
二、集合/字典视图对象
keys()、values()、items()返回的是动态视图,反映底层dict的变化。
配置 = {"主机": "localhost", "端口": 8080, "调试": True}
# 创建视图
键视图 = 配置.keys()
值视图 = 配置.values()
项视图 = 配置.items()
print(f"键视图: {list(键视图)}")
# 修改原字典,视图自动更新
配置["超时"] = 30
配置["主机"] = "192.168.1.1"
print(f"更新后键视图: {list(键视图)}") # 包含新键
print(f"值视图: {list(值视图)}")
# 视图支持集合运算(键视图和项视图)
其他配置 = {"主机": "10.0.0.1", "端口": 9090, "协议": "https"}
交集键 = 配置.keys() & 其他配置.keys()
差集键 = 配置.keys() - 其他配置.keys()
并集键 = 配置.keys() | 其他配置.keys()
print(f"共同的键: {交集键}")
print(f"独有的键: {差集键}")
print(f"所有键: {并集键}")
三、集合运算链式调用
集合的union、intersection等方法可以链式调用,返回新集合。
基础用户 = {"张三", "李四", "王五"}
VIP用户 = {"李四", "赵六", "钱七"}
管理员 = {"王五", "孙八"}
黑名单 = {"赵六"}
# 链式集合运算:找出所有可发送通知的用户
可通知用户 = (基础用户 | VIP用户) - 黑名单
print(f"可通知用户: {可通知用户}")
# 复杂的集合运算链
结果 = 基础用户.intersection(VIP用户).union(管理员).difference(黑名单)
print(f"链式结果: {结果}")
# |=, &=, -=, ^= 原地操作
会话权限 = {"读取", "写入"}
会话权限 |= {"删除"} # 添加权限
print(f"更新后权限: {会话权限}")
四、集合推导式性能优化
集合推导式比循环add方式更快,内部有优化。
import time
def 对比集合构建方式():
"""对比集合推导式和循环add的性能"""
数据量 = 100000
# 使用集合推导式
开始 = time.perf_counter()
集合1 = {i % 5000 for i in range(数据量)}
推导式耗时 = time.perf_counter() - 开始
# 使用for循环add
开始 = time.perf_counter()
集合2 = set()
for i in range(数据量):
集合2.add(i % 5000)
循环耗时 = time.perf_counter() - 开始
print(f"集合推导式: {推导式耗时:.4f}s")
print(f"循环add: {循环耗时:.4f}s")
print(f"推导式快 {循环耗时/推导式耗时:.2f} 倍")
对比集合构建方式()
# 带条件的集合推导式
偶数平方集合 = {x ** 2 for x in range(20) if x % 2 == 0}
print(f"偶数平方集合: {偶数平方集合}")
五、__contains__与in操作符
集合的__contains__方法使用哈希表实现,时间复杂度为O(1)。
def 成员检测性能对比():
"""对比列表和集合的成员检测性能"""
数据量 = 100000
测试集 = set(range(数据量))
测试列表 = list(range(数据量))
# 集合成员检测
开始 = time.perf_counter()
for i in range(10000):
_ = i in 测试集
集合耗时 = time.perf_counter() - 开始
# 列表成员检测
开始 = time.perf_counter()
for i in range(10000):
_ = i in 测试列表
列表耗时 = time.perf_counter() - 开始
print(f"集合__contains__: {集合耗时:.4f}s")
print(f"列表__contains__: {列表耗时:.4f}s")
print(f"集合快 {列表耗时/集合耗时:.0f} 倍")
成员检测性能对比()
六、frozenset的高级应用:缓存与去重
def 生成缓存键(*args, **kwargs):
"""为函数参数生成可哈希的缓存键"""
位置键 = frozenset(args) if len(args) > 1 else args
关键字键 = frozenset(kwargs.items())
return (位置键, 关键字键)
# 使用frozenset做函数结果缓存
from functools import lru_cache
@lru_cache(maxsize=128)
def 统计字频(文本: str, 忽略字符: frozenset = frozenset()):
"""统计文本中字符出现频率"""
频率 = {}
for 字符 in 文本:
if 字符 not in 忽略字符:
频率[字符] = 频率.get(字符, 0) + 1
return 频率
文本 = "hello world"
标点 = frozenset({',', '.', '!', '?'})
结果1 = 统计字频(文本, 标点)
结果2 = 统计字频(文本) # 不带忽略字符
print(f"字频(忽略标点): {结果1}")
七、小结
frozenset作为可哈希的不可变集合,在字典键、集合元素、
缓存键等场景中表现出色。视图对象的动态特性与集合运算
的结合,为字典操作提供了函数式风格的支持。理解这些高级
特性可以写出更高效、更优雅的Python代码。
