掌握Python自定义字典类型:打造自己的映射容器

前言

Python容器类型的常用操作对于一个Python使用者来说应该不陌生,其中字典是一种更复杂的容器结构。但有时候内容容器类型并不能满足我们的需求,我们有时候需要创造新的容器类型来满足需求,这篇文章我们一起看一下如何自定义字典类型?

自定义字典类可以重写哪些方法呢?

通常需要重写以下一些方法:

  • __init__: 初始化方法,用于创建字典实例并进行初始化操作。
  • __getitem__: 获取指定键对应的值。
  • __setitem__: 设置指定键对应的值。
  • __delitem__: 删除指定键及其对应的值。
  • __len__: 返回字典中键值对的数量。
  • __iter__: 返回一个迭代器,用于遍历字典中的所有键。
  • keys(): 返回一个包含字典所有键的迭代器或列表。
  • values(): 返回一个包含字典所有值的迭代器或列表。
  • items(): 返回一个包含所有键值对的迭代器或列表。
  • __contains__: 检查字典是否包含指定的键。

这些方法中,__getitem____setitem____delitem__是实现自定义字典最基本的方法,它们分别用于获取、设置和删除字典中的键值对。另外,__len__方法用于返回字典中键值对的数量,而__iter__方法用于返回一个迭代器,使得我们可以对字典进行迭代操作。

实现场景

统计某个元素在列表中出现的次数,我们来实现这个字典类

方法一:继承dict

python 复制代码
from collections import defaultdict
from collections.abc import MutableMapping
​
​
class CounterDict(dict):
    def __init__(self):
        super().__init__()
        self.counter = defaultdict(int)
​
    def count(self, key):
        self.counter[key] += 1
​
    def __getitem__(self, key):
        return self.counter[key]
​
    def __setitem__(self, key, value):
        self.counter[key] = value
        super().__setitem__(key, value)
​
    def __delitem__(self, key):
        del self.counter[key]
​
    def __len__(self):
        return len(self.counter)
​
    def __iter__(self):
        return iter(self.counter)
​
    def keys(self):
        return self.counter.keys()
​
    def values(self):
        return self.counter.values()
​
    def items(self):
        return self.counter.items()
​
counter = CounterDict()
data = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
​
for item in data:
    counter.count(item)
​
print(counter['apple'])  # 输出:3
print(counter['banana'])  # 输出:2
print(counter['orange'])  # 输出:1
​

CounterDict类继承了基本的字典行为,并添加了额外的计数功能。通过调用count()方法,我们可以将一个元素添加到字典中,并增加其计数值。通过重写特殊方法,比如__getitem____setitem____delitem__,我们可以实现对字典的读取、更新和删除操作。此外,我们还重写了__len____iter__方法,以支持获取字典长度和遍历字典的功能。

这种方法有一些问题,setitem方法重写键赋值操作,此时常规的dkey = value行为会被重写,但如果用d.update()来更新字典内容,是不会触发重写后的键赋值操作逻辑。举个例子:

scss 复制代码
counter = CounterDict()
counter['pear'] = 10
counter.update({'pear': 100})
print(counter) # {'pear': 100}
print(counter['pear']) # 10

那该如何解决这种问题呢,接下来方法二就诞生了

方法二:继承MutableMapping

我们只需对上述代码稍加修改即可,像这样

python 复制代码
from collections import defaultdict
from collections.abc import MutableMapping
​
​
class CounterDict(MutableMapping):
    ......
​
    def __setitem__(self, key, value):
        self.counter[key] = value
​
    ......
​

只需修改这里,其他部分不变,我们再次进行测试

scss 复制代码
counter = CounterDict()
counter['pear'] = 10
counter.update({'pear': 100})
print(counter) # <__main__.CounterDict object at 0x10143d040>
print(counter['pear']) # 100

这样就可以了。

MutableMapping是Python标准库中collections.abc模块提供的一个抽象基类,用于定义可变的映射类型(mapping)的接口规范

最后

因为继承dict来创建自定义字典类型会出现一些问题,为了避免这些问题,collections.abc模块下的MutableMapping抽象类是更好的选择,它不会出现上面的问题。

相关推荐
一晌小贪欢6 分钟前
第22节:相关性分析——协方差、相关系数与热力图解读
开发语言·python·数据分析·pandas·数据可视化
杨超越luckly7 分钟前
Agent应用指南:利用GET请求获取理想汽车门店位置信息
前端·python·html·汽车·可视化
财经资讯数据_灵砚智能8 分钟前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年6月9日
人工智能·python·ai·信息可视化·自然语言处理·ai编程·灵砚智能
love530love8 小时前
LiveTalking 数字人项目 Windows 部署完全指南(EPGF 架构)
人工智能·windows·python·架构·livetalking·epgf
遇事不決洛必達8 小时前
【Python基础】GIL 锁是什么及其对爬虫的影响
爬虫·python·线程·进程·gil锁
星辰徐哥8 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥8 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约8 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee8 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐8 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统