collections模块(高级容器数据类型)一. 认识 collectionscollections是 Python 的内置标准库无需安装即可直接导入。它提供了一些额外的高级数据结构本质上都是基于原生类型的封装与继承用来替代 Python原生的dict、list、set和tuple从而让数据处理变得更加高效和优雅。二. collections中字典相关类型(dict)1. Counter类型 (字典的子类)说明Counter是 Python 原生字典dict的子类继承自dict。作为一种专门为统计设计的类它具备普通字典的所有基本属性和方法同时对其进行了高度的定制化扩展使其能够更方便地进行频次统计操作。在 NLP 的词表构建、词频统计中常用Counter类(1).Counter() - 超级计数器作用作为dict的子类实例化方法它专门用于统计可迭代对象中元素的出现次数。它的键Key是被统计的元素值Value是该元素出现的次数。fromcollectionsimportCounter Counter(iterable_or_mapping)参数可迭代对象 (iterable_or_mapping) 需要被统计的列表、元组、字符串或者是已经包含部分计数的字典。返回值成功 返回一个Counter类型的实例对象表现与字典高度一致内部自动按元素出现的频次进行了整理。示例fromcollectionsimportCounter# 1. 传入列表进行自动计数words_list[apple,banana,apple,orange,banana,apple]word_countsCounter(words_list)print(word_counts)# 结果: Counter({apple: 3, banana: 2, orange: 1})# 2. 像字典一样获取某个元素的次数print(word_counts[apple])# 结果: 3# 3. 遇到不存在的元素不会报错而是返回 0(这是与普通 dict 最大的区别之一)print(word_counts[grape])# 结果: 0(2).most_common() - 提取高频元素作用这是Counter类最强大的专属实例方法它会根据元素的出现次数从高到低排序并返回一个包含元组的列表。这是 NLP 截断低频词、构建词表的最核心方法Counter.most_common(nNone)参数数量 (n) 可选参数。指定返回出现频次排名前n的元素。如果不填则返回所有元素排序后的结果 (int)。返回值成功 返回一个由(元素, 频次)元组组成的列表 (list[tuple])。示例fromcollectionsimportCounter words_list[a,b,b,c,c,c,d,d,d,d]countsCounter(words_list)# 获取频次最高的前 2 个词top_2counts.most_common(2)print(top_2)# 结果: [(d, 4), (c, 3)](3).elements() - 展开统计元素作用返回一个迭代器其中每个元素将重复出现其计数值所代表的次数。常用于将统计好的词频字典“还原”回原始的数据流。Counter.elements()返回值成功 返回一个itertools.chain类型的迭代器对象。注意频次小于 1 的元素会被忽略。示例cCounter(a4,b2,c0,d-2)print(list(c.elements()))# 结果: [a, a, a, a, b, b] (c和d被忽略了)(4).update() 与 subtract() - 批量增减计数作用普通字典的update是直接覆盖同名 Key 的 Value而Counter重写了update它的逻辑是累加同理subtract则是批量相减。Counter.update(iterable_or_mapping)Counter.subtract(iterable_or_mapping)参数可迭代对象 (iterable_or_mapping) 需要新增或扣除计数的数据源。示例cCounter({apple:3,banana:2})# 1. 累加频次 (update)c.update([apple,apple,orange])print(c)# 结果: Counter({apple: 5, banana: 2, orange: 1})# 2. 扣减频次 (subtract)c.subtract({apple:2,banana:5})print(c)# 结果: Counter({apple: 3, orange: 1, banana: -3}) # 允许出现负数2. defaultdict类型 (字典的子类)说明defaultdict是 Python 原生字典dict的子类dict。它与原生字典最大的区别在于当试图访问一个不存在的键时它不会抛出KeyError异常而是会自动调用一个预先设定的工厂函数为这个缺失的键生成一个默认值。(1).defaultdict() - 默认值字典作用创建自带默认值机制的字典。这极大地简化了数据分组、多值映射以及统计的代码逻辑让你无需再手动编写if key not in d:或使用dict.setdefault()。fromcollectionsimportdefaultdict defaultdict(default_factoryNone,/[,...])参数默认值工厂函数 (default_factory) 必须是一个可调用对象如int,list,set或者自定义无参函数。当访问缺失的键时系统会无参调用它来生成默认值。如果传入None它将退化为普通字典的行为找不到键时报错。defaultdict(int)—— 计数器之王无参调用int()默认返回0。场景统计频次。遇到新元素默认初始化为 0然后直接 1。defaultdict(list)—— 分组聚合神器无参调用list()默认返回[]。场景一对多映射。比如把同一班级的学生名字归拢到一个列表里遇到新班级直接.append(名字)绝对不会报错。defaultdict(set)—— 去重分组神器无参调用set()默认返回空集合set()。场景和list类似但自带去重功能。如果你想把同一班级的学生归拢起来又怕名字重复录入用它然后直接调用.add(名字)。defaultdict(lambda: 未知数据)—— 自定义花式默认值无参调用lambda: 未知数据执行后返回字符串未知数据。场景有时候你不想要 0 也不想要空列表你就想要一个特定的默认字符串或数字。既然必须传函数那就当场写一个无需参数的匿名函数lambda传进去返回值成功 返回一个defaultdict实例。查询缺失键时自动赋默认值并返回该默认值。示例fromcollectionsimportdefaultdict# 1. 传入 list 作为工厂函数实现一对多映射 (非常适合做分类/分组聚合)data[(fruit,apple),(fruit,banana),(vegetable,carrot)]group_dictdefaultdict(list)forcategory,itemindata:# 遇到新的 category会自动创建空列表 []并直接进行 append 操作group_dict[category].append(item)print(dict(group_dict))# 结果: {fruit: [apple, banana], vegetable: [carrot]}# 2. 传入 int 作为工厂函数 (默认值为 0)用于计数count_dictdefaultdict(int)count_dict[apple]1# 即使 apple 之前不存在也会默认初始化为 0再 1print(count_dict[apple])# 结果: 1(2).default_factory属性 - 动态修改工厂作用defaultdict将工厂函数保存在实例的default_factory属性中。面试技巧可以在运行时动态修改该属性随时切换默认值生成的逻辑示例ddefaultdict(int)# 默认返回 0print(d[a])# 结果: 0# 动态修改默认值工厂d.default_factorylist# 改为默认返回空列表 []print(d[b])# 结果: []3. OrderedDict类型 (字典的子类)说明OrderedDict也是 Python 原生字典dict的子类继承自dict。作为一种特殊的数据类型它在拥有原生字典全部特性的基础上底层额外维护了一个双向链表以此来严格记录键值对的插入顺序并提供相关的排序和调整操作。(1).OrderedDict() - 有序字典作用OrderedDict类的实例化方法顾名思义是创建一个“记录了元素插入顺序”的字典对象。虽然自 Python 3.7 开始原生的dict也在底层实现了顺序记录但OrderedDict依然具有独特价值。它不仅在代码层面上明确表达了“顺序极其重要”的语义而且提供了原生字典所不具备的专属排序方法。fromcollectionsimportOrderedDict OrderedDict([items])参数初始化数据 (items) 可选参数。可以是包含键值对的元组列表也可以是另一个字典。返回值成功 返回一个OrderedDict类型的实例对象该对象严格保证元素插入顺序。示例fromcollectionsimportOrderedDict odOrderedDict()od[apple]3od[banana]2od[orange]1print(od)# 结果: OrderedDict([(apple, 3), (banana, 2), (orange, 1)])(2).move_to_end() - 调整元素位置作用将一个已经存在的键移动到字典的最前端或最后端。常用于实现 LRU (最近最少使用) 缓存淘汰算法OrderedDict.move_to_end(key,lastTrue)参数键 (key) 需要被移动的目标键。位置 (last) 默认True移动到末尾设为False移动到开头。示例odOrderedDict.fromkeys(abcde)print(od)# OrderedDict([(a, None), (b, None), (c, None), (d, None), (e, None)])od.move_to_end(b)# 移到最后od.move_to_end(d,False)# 移到最前print(list(od.keys()))# 结果: [d, a, c, e, b](3).popitem() - 有序弹出作用弹出并返回字典中的一个(key, value)键值对。由于是有序字典你可以精确控制是弹出 LIFO后进先出还是 FIFO先进先出。OrderedDict.popitem(lastTrue)参数位置 (last) 默认True类似栈弹出最后插入的元素设为False类似队列弹出最先插入的元素。示例odOrderedDict([(a,1),(b,2),(c,3)])print(od.popitem(lastFalse))# 弹出最旧的# 结果: (a, 1)4. UserDict类型 (字典的包装类)说明UserDict是一个专门为了方便开发者“自定义/重写字典功能”而设计的包装基类。避坑指南如果你想自己写一个类来实现一种特殊的字典直接去继承 Python 原生的dict极其容易踩坑因为原生字典底层是用 C 语言写的它自带的许多内置方法不会触发你重写的逻辑。因此官方推荐只要你想自定义字典就继承UserDict它的内部把真正的字典数据存在了一个叫做data的属性里修改起来非常安全。知识联动Hugging Face 分词器返回的那个强大且好用的BatchEncoding对象其底层就是直接继承自UserDict的(1).UserDict() - 字典自定义基类作用作为基类被继承用于派生出带有自定义逻辑的特殊字典对象。开发者通过重写魔术方法如__setitem__、__getitem__可以轻松拦截、监听或修改字典的读写行为。fromcollectionsimportUserDictclassMyCustomDict(UserDict):pass参数初始化数据 (dict, kwargs) 实例化时支持像普通字典一样传入键值对这些数据会被自动保存在对象的self.data属性中。返回值成功 返回一个具有完全字典行为且支持安全定制的自定义对象。示例fromcollectionsimportUserDict# 需求写一个特殊的字典用户存入的任何 Key 都会被强制变成大写classUpperKeyDict(UserDict):# 重写赋值方法 (拦截 dict[key] value 的操作)def__setitem__(self,key,value):# 强制把 key 转大写后存入底层的真实字典 self.data 中self.data[key.upper()]value# 测试我们自己手搓的字典my_dictUpperKeyDict()my_dict[apple]100my_dict[Banana]200print(my_dict)# 结果: {APPLE: 100, BANANA: 200} (所有的 Key 都自动变大写了)# 查看底层的真实数据载体print(type(my_dict.data))# 结果: class dict(2).data 属性 - 获取底层原生字典作用这是UserDict暴露出来的核心属性。当你想把包装后的字典当作最纯粹的 Python 字典传递给其他 C 语言底层库如json.dumps时直接传入self.data可以避免很多序列化错误。示例importjson my_dictUpperKeyDict()my_dict[apple]100# 推荐获取底层真实字典再进行序列化print(json.dumps(my_dict.data))# 结果: {APPLE: 100}三. collections中列表相关类型(list)1. deque类型deque不是任何其他原生基本数据结构的子类deque是一种双端队列。避坑指南如果需要频繁在列表头部插入或删除数据原生的list原生列表在头部操作的时间复杂度是O(N)O(N)O(N)因为要移动其后所有的元素数据量大时会严重卡顿。而deque在两端操作的时间复杂度均为O(1)O(1)O(1)是解决此类性能痛点的完美替代品。(1).deque() - 双端队列实例作用创建一个类似列表的容器支持在两端高效、线程安全地追加和弹出数据。常用于滑动窗口、保留最近 N 条历史记录、以及算法中的广度优先搜索 (BFS)。fromcollectionsimportdeque deque([iterable[,maxlen]])参数可迭代对象 (iterable) 可选。用于初始化队列的数据源如列表、字符串等。最大长度 (maxlen) 可选且非常核心的参数指定队列的最大长度。如果指定了maxlen当队列满了之后再加入新元素另一端的旧元素会被自动挤出丢弃。如果不指定队列则可以无限增长。返回值成功 返回一个deque类型的实例对象支持类似列表的索引访问且两端操作极快。示例fromcollectionsimportdeque# 1. 基础两端高效操作ddeque([b,c])d.append(d)# 尾部插入d.appendleft(a)# 头部插入 (比 list.insert(0, a) 性能高极多)print(d)# 结果: deque([a, b, c, d])# 2. 限制最大长度 (maxlen) 的妙用保留最近的 N 条记录# 例如构建一个大小为 3 的滑动窗口historydeque(maxlen3)history.append(1)history.append(2)history.append(3)print(history)# 结果: deque([1, 2, 3], maxlen3)# 继续插入新元素 4最左侧最旧的 1 会被自动挤出去history.append(4)print(history)# 结果: deque([2, 3, 4], maxlen3)(2).append() 与 pop() - 尾插/尾删作用在双端队列的尾部最右侧执行插入和弹出。由于这是最常规的数据操作方向官方为了兼容原生list的代码习惯没有给它们加right后缀而是直接沿用了原生的命名。示例ddeque([a,b])d.append(c)# 尾部插入print(d)# 结果: deque([a, b, c])right_vald.pop()# 尾部高效弹出print(right_val)# 结果: c(3).appendleft() 与 popleft() - 头插/头删作用在双端队列的头部最左侧执行插入和弹出这是替代原生list.insert(0, x)和list.pop(0)的绝对主力方法。示例ddeque([b,c])d.appendleft(a)# 头部插入print(d)# 结果: deque([a, b, c])left_vald.popleft()# 头部弹出print(left_val)# 结果: a(4).extendleft() - 头部批量插入作用将另一个可迭代对象的元素批量插入到队列头部。注由于它是将元素依次插入头部最终队列中的元素顺序会和传入的顺序正好相反示例ddeque([4,5])d.extendleft([1,2,3])print(d)# 结果: deque([3, 2, 1, 4, 5]) # 注意 1,2,3 的顺序反转了(5).rotate() - 轮转队列作用将队列中的所有元素向右或向左循环移动指定的步数。无需你自己手写切片重组代码常用于算法题中的轮转数组、字符串移位。deque.rotate(n1)参数步数 (n) 传入正数向右循环移动传入负数向左循环移动。示例ddeque([1,2,3,4,5])d.rotate(2)# 向右循环移 2 步print(d)# 结果: deque([4, 5, 1, 2, 3])d.rotate(-1)# 向左循环移 1 步print(d)# 结果: deque([5, 1, 2, 3, 4])四.collections中元组相关类型(tuple)1. namedtuple类型 (元组的类工厂函数)说明namedtuple本质上是一个“用来生成元组子类的工厂函数”。普通的tuple只能通过数字下标如person[0]来访问元素代码可读性极差。而namedtuple允许你为元组的每个位置赋予一个“名字”字段名让你既能像原生元组一样享受高内存效率和不可变性又能像对象一样通过点语法如person.name优雅地访问数据。注为什么namedtuple的专属方法都带有前缀下划线如_make,_asdict在 Python 中下划线通常代表私有方法但这里是个例外官方故意加下划线是为了防止你定义的“字段名”和这些自带方法的名字发生冲突。比如你的元组里恰好有一个字段叫make如果自带方法叫make()就会乱套所以官方将其命名为_make()。(1). namedtuple() - 定义并创建具名元组类作用工厂函数。通过传入类名和字段名列表当场“生产”出一个专属的元组子类。fromcollectionsimportnamedtuple namedtuple(typename,field_names)参数类名 (typename) 字符串。你想要创建的新元组子类的名字。字段名 (field_names) 可以是由字符串组成的列表[x, y]也可以是用空格/逗号隔开的单字符串x y。返回值成功 返回一个全新的、定制化的“元组子类”你可以用它去实例化具体的数据对象。示例fromcollectionsimportnamedtuple# 1. 用工厂函数生产一个叫做 Point 的类包含 x 和 y 两个坐标字段Pointnamedtuple(Point,[x,y])# 2. 像使用普通类一样实例化一个坐标点对象pPoint(11,y22)# 3. 核心优势通过字段名直接访问代码极具可读性print(p.x,p.y)# 结果: 11 22# 4. 同时完美兼容普通元组的特性 (支持解包和数字索引)x_val,y_valpprint(p[0],x_val)# 结果: 11 11(2). _make() - 批量转化具名元组作用这是一个类方法。它可以直接将一个现有的可迭代对象如列表、元组批量包装、实例化为一个具名元组对象。NewClass._make(iterable)参数可迭代对象 (iterable) 包含具体数据的列表、元组等其元素数量必须与具名元组的字段数完全一致。示例fromcollectionsimportnamedtuple Pointnamedtuple(Point,[x,y])# 假设我们收到了数据库或表格传来的一行数据列表data_list[100,200]# 使用 _make 快速把列表数据转化为 Point 对象p_newPoint._make(data_list)print(p_new)# 结果: Point(x100, y200)(3). _asdict() - 字典化映射作用将具名元组对象转换为一个高阶的dict在 Python 3.8 中返回普通dict在此之前返回OrderedDict。常用于将元组数据优雅地转化为 JSON 格式输出。instance._asdict()示例fromcollectionsimportnamedtuple Pointnamedtuple(Point,[x,y])pPoint(x5,y10)# 转化为字典结构p_dictp._asdict()print(p_dict)# 结果: {x: 5, y: 10}(4). _replace() - 字段值替换作用替换当前对象中指定字段的值。注由于元组是不可变的此操作并不会直接修改原对象而是当场为你克隆并返回一个修改后的全新具名元组对象。instance._replace(**kwargs)示例pPoint(x1,y2)# 尝试修改 x 的值原对象 p 保持不变p_modifiedp._replace(x100)print(p)# 原对象没变结果: Point(x1, y2)print(p_modified)# 生成了新对象结果: Point(x100, y2)
LLM系列:1.python入门:18.collections模块(高级容器数据类型)
collections模块(高级容器数据类型)一. 认识 collectionscollections是 Python 的内置标准库无需安装即可直接导入。它提供了一些额外的高级数据结构本质上都是基于原生类型的封装与继承用来替代 Python原生的dict、list、set和tuple从而让数据处理变得更加高效和优雅。二. collections中字典相关类型(dict)1. Counter类型 (字典的子类)说明Counter是 Python 原生字典dict的子类继承自dict。作为一种专门为统计设计的类它具备普通字典的所有基本属性和方法同时对其进行了高度的定制化扩展使其能够更方便地进行频次统计操作。在 NLP 的词表构建、词频统计中常用Counter类(1).Counter() - 超级计数器作用作为dict的子类实例化方法它专门用于统计可迭代对象中元素的出现次数。它的键Key是被统计的元素值Value是该元素出现的次数。fromcollectionsimportCounter Counter(iterable_or_mapping)参数可迭代对象 (iterable_or_mapping) 需要被统计的列表、元组、字符串或者是已经包含部分计数的字典。返回值成功 返回一个Counter类型的实例对象表现与字典高度一致内部自动按元素出现的频次进行了整理。示例fromcollectionsimportCounter# 1. 传入列表进行自动计数words_list[apple,banana,apple,orange,banana,apple]word_countsCounter(words_list)print(word_counts)# 结果: Counter({apple: 3, banana: 2, orange: 1})# 2. 像字典一样获取某个元素的次数print(word_counts[apple])# 结果: 3# 3. 遇到不存在的元素不会报错而是返回 0(这是与普通 dict 最大的区别之一)print(word_counts[grape])# 结果: 0(2).most_common() - 提取高频元素作用这是Counter类最强大的专属实例方法它会根据元素的出现次数从高到低排序并返回一个包含元组的列表。这是 NLP 截断低频词、构建词表的最核心方法Counter.most_common(nNone)参数数量 (n) 可选参数。指定返回出现频次排名前n的元素。如果不填则返回所有元素排序后的结果 (int)。返回值成功 返回一个由(元素, 频次)元组组成的列表 (list[tuple])。示例fromcollectionsimportCounter words_list[a,b,b,c,c,c,d,d,d,d]countsCounter(words_list)# 获取频次最高的前 2 个词top_2counts.most_common(2)print(top_2)# 结果: [(d, 4), (c, 3)](3).elements() - 展开统计元素作用返回一个迭代器其中每个元素将重复出现其计数值所代表的次数。常用于将统计好的词频字典“还原”回原始的数据流。Counter.elements()返回值成功 返回一个itertools.chain类型的迭代器对象。注意频次小于 1 的元素会被忽略。示例cCounter(a4,b2,c0,d-2)print(list(c.elements()))# 结果: [a, a, a, a, b, b] (c和d被忽略了)(4).update() 与 subtract() - 批量增减计数作用普通字典的update是直接覆盖同名 Key 的 Value而Counter重写了update它的逻辑是累加同理subtract则是批量相减。Counter.update(iterable_or_mapping)Counter.subtract(iterable_or_mapping)参数可迭代对象 (iterable_or_mapping) 需要新增或扣除计数的数据源。示例cCounter({apple:3,banana:2})# 1. 累加频次 (update)c.update([apple,apple,orange])print(c)# 结果: Counter({apple: 5, banana: 2, orange: 1})# 2. 扣减频次 (subtract)c.subtract({apple:2,banana:5})print(c)# 结果: Counter({apple: 3, orange: 1, banana: -3}) # 允许出现负数2. defaultdict类型 (字典的子类)说明defaultdict是 Python 原生字典dict的子类dict。它与原生字典最大的区别在于当试图访问一个不存在的键时它不会抛出KeyError异常而是会自动调用一个预先设定的工厂函数为这个缺失的键生成一个默认值。(1).defaultdict() - 默认值字典作用创建自带默认值机制的字典。这极大地简化了数据分组、多值映射以及统计的代码逻辑让你无需再手动编写if key not in d:或使用dict.setdefault()。fromcollectionsimportdefaultdict defaultdict(default_factoryNone,/[,...])参数默认值工厂函数 (default_factory) 必须是一个可调用对象如int,list,set或者自定义无参函数。当访问缺失的键时系统会无参调用它来生成默认值。如果传入None它将退化为普通字典的行为找不到键时报错。defaultdict(int)—— 计数器之王无参调用int()默认返回0。场景统计频次。遇到新元素默认初始化为 0然后直接 1。defaultdict(list)—— 分组聚合神器无参调用list()默认返回[]。场景一对多映射。比如把同一班级的学生名字归拢到一个列表里遇到新班级直接.append(名字)绝对不会报错。defaultdict(set)—— 去重分组神器无参调用set()默认返回空集合set()。场景和list类似但自带去重功能。如果你想把同一班级的学生归拢起来又怕名字重复录入用它然后直接调用.add(名字)。defaultdict(lambda: 未知数据)—— 自定义花式默认值无参调用lambda: 未知数据执行后返回字符串未知数据。场景有时候你不想要 0 也不想要空列表你就想要一个特定的默认字符串或数字。既然必须传函数那就当场写一个无需参数的匿名函数lambda传进去返回值成功 返回一个defaultdict实例。查询缺失键时自动赋默认值并返回该默认值。示例fromcollectionsimportdefaultdict# 1. 传入 list 作为工厂函数实现一对多映射 (非常适合做分类/分组聚合)data[(fruit,apple),(fruit,banana),(vegetable,carrot)]group_dictdefaultdict(list)forcategory,itemindata:# 遇到新的 category会自动创建空列表 []并直接进行 append 操作group_dict[category].append(item)print(dict(group_dict))# 结果: {fruit: [apple, banana], vegetable: [carrot]}# 2. 传入 int 作为工厂函数 (默认值为 0)用于计数count_dictdefaultdict(int)count_dict[apple]1# 即使 apple 之前不存在也会默认初始化为 0再 1print(count_dict[apple])# 结果: 1(2).default_factory属性 - 动态修改工厂作用defaultdict将工厂函数保存在实例的default_factory属性中。面试技巧可以在运行时动态修改该属性随时切换默认值生成的逻辑示例ddefaultdict(int)# 默认返回 0print(d[a])# 结果: 0# 动态修改默认值工厂d.default_factorylist# 改为默认返回空列表 []print(d[b])# 结果: []3. OrderedDict类型 (字典的子类)说明OrderedDict也是 Python 原生字典dict的子类继承自dict。作为一种特殊的数据类型它在拥有原生字典全部特性的基础上底层额外维护了一个双向链表以此来严格记录键值对的插入顺序并提供相关的排序和调整操作。(1).OrderedDict() - 有序字典作用OrderedDict类的实例化方法顾名思义是创建一个“记录了元素插入顺序”的字典对象。虽然自 Python 3.7 开始原生的dict也在底层实现了顺序记录但OrderedDict依然具有独特价值。它不仅在代码层面上明确表达了“顺序极其重要”的语义而且提供了原生字典所不具备的专属排序方法。fromcollectionsimportOrderedDict OrderedDict([items])参数初始化数据 (items) 可选参数。可以是包含键值对的元组列表也可以是另一个字典。返回值成功 返回一个OrderedDict类型的实例对象该对象严格保证元素插入顺序。示例fromcollectionsimportOrderedDict odOrderedDict()od[apple]3od[banana]2od[orange]1print(od)# 结果: OrderedDict([(apple, 3), (banana, 2), (orange, 1)])(2).move_to_end() - 调整元素位置作用将一个已经存在的键移动到字典的最前端或最后端。常用于实现 LRU (最近最少使用) 缓存淘汰算法OrderedDict.move_to_end(key,lastTrue)参数键 (key) 需要被移动的目标键。位置 (last) 默认True移动到末尾设为False移动到开头。示例odOrderedDict.fromkeys(abcde)print(od)# OrderedDict([(a, None), (b, None), (c, None), (d, None), (e, None)])od.move_to_end(b)# 移到最后od.move_to_end(d,False)# 移到最前print(list(od.keys()))# 结果: [d, a, c, e, b](3).popitem() - 有序弹出作用弹出并返回字典中的一个(key, value)键值对。由于是有序字典你可以精确控制是弹出 LIFO后进先出还是 FIFO先进先出。OrderedDict.popitem(lastTrue)参数位置 (last) 默认True类似栈弹出最后插入的元素设为False类似队列弹出最先插入的元素。示例odOrderedDict([(a,1),(b,2),(c,3)])print(od.popitem(lastFalse))# 弹出最旧的# 结果: (a, 1)4. UserDict类型 (字典的包装类)说明UserDict是一个专门为了方便开发者“自定义/重写字典功能”而设计的包装基类。避坑指南如果你想自己写一个类来实现一种特殊的字典直接去继承 Python 原生的dict极其容易踩坑因为原生字典底层是用 C 语言写的它自带的许多内置方法不会触发你重写的逻辑。因此官方推荐只要你想自定义字典就继承UserDict它的内部把真正的字典数据存在了一个叫做data的属性里修改起来非常安全。知识联动Hugging Face 分词器返回的那个强大且好用的BatchEncoding对象其底层就是直接继承自UserDict的(1).UserDict() - 字典自定义基类作用作为基类被继承用于派生出带有自定义逻辑的特殊字典对象。开发者通过重写魔术方法如__setitem__、__getitem__可以轻松拦截、监听或修改字典的读写行为。fromcollectionsimportUserDictclassMyCustomDict(UserDict):pass参数初始化数据 (dict, kwargs) 实例化时支持像普通字典一样传入键值对这些数据会被自动保存在对象的self.data属性中。返回值成功 返回一个具有完全字典行为且支持安全定制的自定义对象。示例fromcollectionsimportUserDict# 需求写一个特殊的字典用户存入的任何 Key 都会被强制变成大写classUpperKeyDict(UserDict):# 重写赋值方法 (拦截 dict[key] value 的操作)def__setitem__(self,key,value):# 强制把 key 转大写后存入底层的真实字典 self.data 中self.data[key.upper()]value# 测试我们自己手搓的字典my_dictUpperKeyDict()my_dict[apple]100my_dict[Banana]200print(my_dict)# 结果: {APPLE: 100, BANANA: 200} (所有的 Key 都自动变大写了)# 查看底层的真实数据载体print(type(my_dict.data))# 结果: class dict(2).data 属性 - 获取底层原生字典作用这是UserDict暴露出来的核心属性。当你想把包装后的字典当作最纯粹的 Python 字典传递给其他 C 语言底层库如json.dumps时直接传入self.data可以避免很多序列化错误。示例importjson my_dictUpperKeyDict()my_dict[apple]100# 推荐获取底层真实字典再进行序列化print(json.dumps(my_dict.data))# 结果: {APPLE: 100}三. collections中列表相关类型(list)1. deque类型deque不是任何其他原生基本数据结构的子类deque是一种双端队列。避坑指南如果需要频繁在列表头部插入或删除数据原生的list原生列表在头部操作的时间复杂度是O(N)O(N)O(N)因为要移动其后所有的元素数据量大时会严重卡顿。而deque在两端操作的时间复杂度均为O(1)O(1)O(1)是解决此类性能痛点的完美替代品。(1).deque() - 双端队列实例作用创建一个类似列表的容器支持在两端高效、线程安全地追加和弹出数据。常用于滑动窗口、保留最近 N 条历史记录、以及算法中的广度优先搜索 (BFS)。fromcollectionsimportdeque deque([iterable[,maxlen]])参数可迭代对象 (iterable) 可选。用于初始化队列的数据源如列表、字符串等。最大长度 (maxlen) 可选且非常核心的参数指定队列的最大长度。如果指定了maxlen当队列满了之后再加入新元素另一端的旧元素会被自动挤出丢弃。如果不指定队列则可以无限增长。返回值成功 返回一个deque类型的实例对象支持类似列表的索引访问且两端操作极快。示例fromcollectionsimportdeque# 1. 基础两端高效操作ddeque([b,c])d.append(d)# 尾部插入d.appendleft(a)# 头部插入 (比 list.insert(0, a) 性能高极多)print(d)# 结果: deque([a, b, c, d])# 2. 限制最大长度 (maxlen) 的妙用保留最近的 N 条记录# 例如构建一个大小为 3 的滑动窗口historydeque(maxlen3)history.append(1)history.append(2)history.append(3)print(history)# 结果: deque([1, 2, 3], maxlen3)# 继续插入新元素 4最左侧最旧的 1 会被自动挤出去history.append(4)print(history)# 结果: deque([2, 3, 4], maxlen3)(2).append() 与 pop() - 尾插/尾删作用在双端队列的尾部最右侧执行插入和弹出。由于这是最常规的数据操作方向官方为了兼容原生list的代码习惯没有给它们加right后缀而是直接沿用了原生的命名。示例ddeque([a,b])d.append(c)# 尾部插入print(d)# 结果: deque([a, b, c])right_vald.pop()# 尾部高效弹出print(right_val)# 结果: c(3).appendleft() 与 popleft() - 头插/头删作用在双端队列的头部最左侧执行插入和弹出这是替代原生list.insert(0, x)和list.pop(0)的绝对主力方法。示例ddeque([b,c])d.appendleft(a)# 头部插入print(d)# 结果: deque([a, b, c])left_vald.popleft()# 头部弹出print(left_val)# 结果: a(4).extendleft() - 头部批量插入作用将另一个可迭代对象的元素批量插入到队列头部。注由于它是将元素依次插入头部最终队列中的元素顺序会和传入的顺序正好相反示例ddeque([4,5])d.extendleft([1,2,3])print(d)# 结果: deque([3, 2, 1, 4, 5]) # 注意 1,2,3 的顺序反转了(5).rotate() - 轮转队列作用将队列中的所有元素向右或向左循环移动指定的步数。无需你自己手写切片重组代码常用于算法题中的轮转数组、字符串移位。deque.rotate(n1)参数步数 (n) 传入正数向右循环移动传入负数向左循环移动。示例ddeque([1,2,3,4,5])d.rotate(2)# 向右循环移 2 步print(d)# 结果: deque([4, 5, 1, 2, 3])d.rotate(-1)# 向左循环移 1 步print(d)# 结果: deque([5, 1, 2, 3, 4])四.collections中元组相关类型(tuple)1. namedtuple类型 (元组的类工厂函数)说明namedtuple本质上是一个“用来生成元组子类的工厂函数”。普通的tuple只能通过数字下标如person[0]来访问元素代码可读性极差。而namedtuple允许你为元组的每个位置赋予一个“名字”字段名让你既能像原生元组一样享受高内存效率和不可变性又能像对象一样通过点语法如person.name优雅地访问数据。注为什么namedtuple的专属方法都带有前缀下划线如_make,_asdict在 Python 中下划线通常代表私有方法但这里是个例外官方故意加下划线是为了防止你定义的“字段名”和这些自带方法的名字发生冲突。比如你的元组里恰好有一个字段叫make如果自带方法叫make()就会乱套所以官方将其命名为_make()。(1). namedtuple() - 定义并创建具名元组类作用工厂函数。通过传入类名和字段名列表当场“生产”出一个专属的元组子类。fromcollectionsimportnamedtuple namedtuple(typename,field_names)参数类名 (typename) 字符串。你想要创建的新元组子类的名字。字段名 (field_names) 可以是由字符串组成的列表[x, y]也可以是用空格/逗号隔开的单字符串x y。返回值成功 返回一个全新的、定制化的“元组子类”你可以用它去实例化具体的数据对象。示例fromcollectionsimportnamedtuple# 1. 用工厂函数生产一个叫做 Point 的类包含 x 和 y 两个坐标字段Pointnamedtuple(Point,[x,y])# 2. 像使用普通类一样实例化一个坐标点对象pPoint(11,y22)# 3. 核心优势通过字段名直接访问代码极具可读性print(p.x,p.y)# 结果: 11 22# 4. 同时完美兼容普通元组的特性 (支持解包和数字索引)x_val,y_valpprint(p[0],x_val)# 结果: 11 11(2). _make() - 批量转化具名元组作用这是一个类方法。它可以直接将一个现有的可迭代对象如列表、元组批量包装、实例化为一个具名元组对象。NewClass._make(iterable)参数可迭代对象 (iterable) 包含具体数据的列表、元组等其元素数量必须与具名元组的字段数完全一致。示例fromcollectionsimportnamedtuple Pointnamedtuple(Point,[x,y])# 假设我们收到了数据库或表格传来的一行数据列表data_list[100,200]# 使用 _make 快速把列表数据转化为 Point 对象p_newPoint._make(data_list)print(p_new)# 结果: Point(x100, y200)(3). _asdict() - 字典化映射作用将具名元组对象转换为一个高阶的dict在 Python 3.8 中返回普通dict在此之前返回OrderedDict。常用于将元组数据优雅地转化为 JSON 格式输出。instance._asdict()示例fromcollectionsimportnamedtuple Pointnamedtuple(Point,[x,y])pPoint(x5,y10)# 转化为字典结构p_dictp._asdict()print(p_dict)# 结果: {x: 5, y: 10}(4). _replace() - 字段值替换作用替换当前对象中指定字段的值。注由于元组是不可变的此操作并不会直接修改原对象而是当场为你克隆并返回一个修改后的全新具名元组对象。instance._replace(**kwargs)示例pPoint(x1,y2)# 尝试修改 x 的值原对象 p 保持不变p_modifiedp._replace(x100)print(p)# 原对象没变结果: Point(x1, y2)print(p_modified)# 生成了新对象结果: Point(x100, y2)