当前位置: 首页 > news >正文

python collections

## Python collections 模块那些事

Python 这门语言,很多人一开始觉得它简单,写着写着却会发现,有些东西就像那句“看似寻常最奇崛”。collections 模块就是这种存在。它不是语言的基础部分,但它在标准库中占据了一个特别的位置——如果应用得当,它能把写代码这件事从“代码能跑”变成“代码让人觉得舒服”。

它是什么

collections 是 Python 标准库中的一个模块,专门用来扩展内置的数据类型。内置的那些 list、dict、tuple 在大部分场景下够用,但总有一些特殊情况,比如你要计数、要维护有顺序的字典、要创建轻量级的数据容器。这些时候如果只靠内置类型去硬拼,代码很快就会变得冗长且难以维护。

collections 本质上是一组容器数据类型的集合,它们不是代替内建类型,而是在内建类型的基础上提供更精确的工具。好比修车,扳手和螺丝刀当然够用,但遇到某些特殊螺丝,有专用工具能省很多力气。

它能做什么

用一个生活中的场景去理解也许会容易一些。假设你在管理一个图书馆,读者可以借书、还书、预约。这个过程中会遇到很多情况:

  • 记录每本书被借出的次数。普通 dict 能记录,但每次更新都要判断键是否存在、值是否为 None。Counter就是为这种事准备的,直接加或者初始化都方便。

  • 需要记住读者预约的顺序,同时又能快速删除某条记录。如果只用 dict,顺序就丢了;如果只用 list,查找速度又慢。OrderedDict保留了插入顺序,兼顾了查找效率和顺序。

  • 希望默认情况下取一个不存在的键时不报错,而是返回一个默认值。普通的 dict 得用setdefault或者defaultdict,看着就麻烦。defaultdict直接帮你处理了这种事。

  • 如果你想要一个堆栈和队列的结合体,允许两边都可以高效地添加或弹出元素。deque就是专门干这个的。

  • 还有一种场景,想定义一个轻量级的、不可变的数据结构,就像 C 语言的结构体那样,但又同时具备 tuple 的不可变性和 dict 的键访问能力。namedtuple正合适。

  • 当你定义复杂的类,既要实现属性访问,又要保证不可变,或者要自定义散列逻辑。UserDictUserListUserString这三个东西很少被提及,但它们是继承自定义行为的好帮手。

坦白说,很多开发者多年使用 Python 也不一定认识UserDict,但其他几个几乎每天都在用。

怎么使用

先从最常用的defaultdict说起。假设你要统计一个列表中字符出现的次数,用普通 dict:

data=['a','b','a','c','b','a']count={}forchindata:ifchnotincount:count[ch]=0count[ch]+=1

换成defaultdict

fromcollectionsimportdefaultdict count=defaultdict(int)forchindata:count[ch]+=1

当一个键不存在时,defaultdict会调用int()返回 0,代码可读性提升很多。

Counter把这件事又简化了一层:

fromcollectionsimportCounter count=Counter(data)# 一行搞定

Counter还提供了most_common(n)的方法,直接取出现次数最多的前 n 个元素,这在分析日志、词频统计时非常有用。

再说namedtuple。假设你在处理地理坐标:

fromcollectionsimportnamedtuple Point=namedtuple('Point',['x','y'])p=Point(10,20)print(p.x)# 10print(p[0])# 10

它既可以像 tuple 一样按索引访问,也可以像对象一样按属性访问。这种方式在函数返回多个值时尤其有用,比普通 tuple 更自文档化,也比写一个完整的类更轻量。

deque的两端操作性能与 list 完全不同。list 在头部插入是 O(n),deque 是 O(1)。当你需要实现一个固定长度的滑动窗口或历史记录时:

fromcollectionsimportdeque history=deque(maxlen=5)history.append('a')history.append('b')history.append('c')history.append('d')history.append('e')history.append('f')# 此时 'a' 自动被移除

maxlen参数自动淘汰旧元素,省去了手动判断长度并删除元素的麻烦。

OrderedDict在 Python 3.7 之后确实失去了部分光芒,因为普通 dict 也保留了插入顺序。但它仍然有用武之地——当你需要move_to_end这样的方法时,普通 dict 做不到。比如实现一个 LRU(最近最少使用)缓存,OrderedDict是天然的选择:

fromcollectionsimportOrderedDictclassLRUCache:def__init__(self,capacity):self.cache=OrderedDict()self.capacity=capacitydefget(self,key):ifkeynotinself.cache:return-1self.cache.move_to_end(key)returnself.cache[key]defput(self,key,value):ifkeyinself.cache:self.cache.move_to_end(key)self.cache[key]=valueiflen(self.cache)>self.capacity:self.cache.popitem(last=False)

最佳实践

实际项目中,用defaultdict而不是多次setdefault能显著减少缩进层级。如果你发现一段代码里有三个以上的if key in dict判断,大概率能改用defaultdictCounter重写。

namedtuple在替代大量元组解包时效果很好。比如数据库查询返回的每一行,如果用一个 namedtuple 来表示,比用 dict 更节省内存,而且属性访问比索引访问更安全。不过要注意,namedtuple 是不可变的,要修改就得新建一个_replace

deque的场景相对集中。如果你处理的是 IO 缓冲区、消息队列、或者需要按顺序处理任务,deque比 list 更合适。但如果你只是做简单的 append / pop,list 就已经够用了。

对于Counter,它不仅仅能计数。两个 Counter 可以直接做加减运算,这在处理语料库或流量统计时非常方便。比如统计两天的访问数据:

day1=Counter({'a':3,'b':2})day2=Counter({'a':1,'b':4,'c':2})total=day1+day2# {'a': 4, 'b': 6, 'c': 2}

OrderedDict的用途在大多数情况下可以被普通 dict 取代。只有当需要move_to_endpopitem这种操作时,它才有不可替代性。

另外推荐一个冷门但实用的组合:ChainMap。当你需要把多个字典合并成一个逻辑整体,同时又不希望破坏原始字典时,可以用它。比如处理多层配置(系统配置 -> 用户配置 -> 命令行参数),ChainMap能按优先级查找。

和同类技术对比

如果不使用 collections,能替代defaultdictCounter这类工具的方式无非是写更多条件判断代码。这不算同类技术对比,更像是“有工具 vs 纯手写”的比较。

第三方库方面,有时我会看到有人用pandas做简单计数 —— 杀鸡用牛刀。Pandas 的Series.value_counts()Counter功能类似,但加入 pandas 这个依赖库仅仅为了做计数,并不划算。同样情况还出现在iteration_utilitiessortedcontainers等库中,它们提供了更多的数据结构,但对于基本需求,collections 已经自给自足。

真正与 collections 形成竞争者的是 Python 自身的发展。随着 Python 版本的演进,一些 collections 的功能被内置类型吸收。前面说过,Python 3.7+ 的 dict 保留了插入顺序。Python 3.10+ 中dataclasses的出现又让namedtuple显得更“朴素”一些 —— dataclass 提供了更多灵活性,能定义方法、默认值、类型注解。

但这并不意味着 collections 过时了。namedtuple创建的对象比 dataclass 更轻量,内存占用更小,代码也更简洁。如果只需要一个简单的、不可变的数据容器,namedtuple仍然是最佳选择。

在处理海量数据时,collections 也提供了性能优势。比如用deque代替 list 做队列操作,用Counter代替手写字典计数,这些差距在数据规模小时不明显,当数据量上升到百万级别时,collections 的工具通常经过底层优化,表现得更好。

整体来说,collections 模块是 Python 标准库中最实用的“磨刀不误砍柴工”例子。它不炫技,不华丽,但只要用对了地方,它总能让你的代码变得干净、容易维护,还能跑得快一些。

http://www.jsqmd.com/news/689879/

相关文章:

  • 建筑机器人系统:自主钻孔与动态避障技术解析
  • Windows 11任务栏拖放修复:5分钟恢复你熟悉的高效操作体验
  • 第二章 目录与文件管理(CentOS 7.9 入门+企业生产版)【20260423】001篇
  • ESP32混合I2C总线实战:硬件从机与软件主机协同驱动多传感器
  • LilyGO T-Display-S3开发板评测与开发指南
  • MovieLens个性化推荐系统实战(一):数据洞察与特征工程(数据清洗、特征构建)
  • 如何在5分钟内为你的网站添加一个会聊天的Live2D动画伙伴?
  • 【Docker】从零构建Conda环境镜像:解决激活难题与生产级最佳实践
  • MATLAB优化建模:当两个连续变量相乘时,除了大M法还能怎么线性化?
  • 2026成都GEO优化公司深度测评:本土标杆橙鱼传媒全域AI流量布局解析 - TOP10品牌推荐榜单
  • 大模型真的“理解”现实世界吗?研究表明它们确实理解
  • 第4集:故障自愈 Agent 实战!重启服务、清理磁盘、自动回滚的面试艺术
  • 给你的STM32项目加个‘U盘’:基于W25Q128和HAL库的文件系统(FatFs)移植实战
  • 玻璃---暖边还是氩气?(下)
  • 2026年江苏一人公司法律顾问选择指南:专业律师的甄别之道与何沈君律师深度解析 - 2026年企业推荐榜
  • 【Unity游戏模板】Sort Match Color Puzzle 一款能赚钱的三消替代游戏项目架构深度分析
  • 04月23日AI每日参考:Google推出AI芯片挑战Nvidia,Workspace升级AI助手
  • 销售拓客全流程赋能:企业级销售智能体落地完整解决方案 —— 2026技术路径与选型实测指南
  • 华为入局智能眼镜赛道,“百镜大战”谁能熬过漫长暗战期?
  • 现代C内存安全编码规范2026落地指南(工业级嵌入式/云原生双场景验证版)
  • 告别手忙脚乱:GSE宏编译器如何让你的魔兽世界操作效率翻倍
  • OpenClaw实操指南25|必装6个基础技能:find-skills/skill-creator/mcp-builder,逐一实战
  • Falcon-H1混合架构与BitNet量化技术解析
  • 零代码部署GME多模态向量:小白也能玩转图文跨模态搜索
  • 混合云架构适配:企业级智能体灵活部署完整方案与最佳实践 | 2026企业自动化选型硬核指南
  • 半导体工程师必看:手把手教你用TCAD仿真优化场限环(FLR)间距,提升器件击穿电压
  • 履带消防机器人电池设计方案(高温/防火/高倍率/高安全系统)【浩博电池】
  • 客户老是忘跟?我用2小时做了个自动提醒系统,销售直接少丢30%单
  • 智读致用|《一人企业》2:放弃扩张执念,保持小规模,才是创业者的顶级清醒
  • TerraMaster D1 SSD Plus硬盘盒评测:Thunderbolt 4/USB4性能解析