掌握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方法重写键赋值操作,此时常规的d[key] = 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抽象类是更好的选择,它不会出现上面的问题。

相关推荐
Hgfdsaqwr3 小时前
Django全栈开发入门:构建一个博客系统
jvm·数据库·python
开发者小天3 小时前
python中For Loop的用法
java·服务器·python
老百姓懂点AI3 小时前
[RAG实战] 向量数据库选型与优化:智能体来了(西南总部)AI agent指挥官的长短期记忆架构设计
python
喵手5 小时前
Python爬虫零基础入门【第九章:实战项目教学·第15节】搜索页采集:关键词队列 + 结果去重 + 反爬友好策略!
爬虫·python·爬虫实战·python爬虫工程化实战·零基础python爬虫教学·搜索页采集·关键词队列
Suchadar5 小时前
if判断语句——Python
开发语言·python
ʚB҉L҉A҉C҉K҉.҉基҉德҉^҉大5 小时前
自动化机器学习(AutoML)库TPOT使用指南
jvm·数据库·python
喵手6 小时前
Python爬虫零基础入门【第九章:实战项目教学·第14节】表格型页面采集:多列、多行、跨页(通用表格解析)!
爬虫·python·python爬虫实战·python爬虫工程化实战·python爬虫零基础入门·表格型页面采集·通用表格解析
毕设源码-钟学长6 小时前
【开题答辩全过程】以 基于SpringBoot的智能书城推荐系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
0思必得06 小时前
[Web自动化] 爬虫之API请求
前端·爬虫·python·selenium·自动化
莫问前路漫漫6 小时前
WinMerge v2.16.41 中文绿色版深度解析:文件对比与合并的全能工具
java·开发语言·python·jdk·ai编程