Python Cookbook-5.14 给字典类型增加排名功能

任务

你需要用字典存储一些键和“分数”的映射关系。你经常需要以自然顺序(即以分数的升序)访问键和分数值,并能够根据那个顺序检查一个键的排名。对这个问题,用dict 似乎不太合适。

解决方案

我们可以使用 dict 的子类,根据需要增加或者重写一些方法。在我们使用多继承、将UserDict.DictMixin 放置在基类 dict、并仔细安排各种方法的委托或重写之前,我们可以设法获得一种美妙的平衡,既拥有极好的性能又避免了编写一些冗余代码。

我们可以在文档字符串中加入很多示例,还可以用标准库的 doctest 模块来提供单元测试的功能,这也能够确保我们在文档字符串中编写的例子的准确性:

#!/usr/bin/env python
'''一个反映键到分数的映射的字典'''
from bisect import bisect_left,insort_left
import UserDict
class Ratings(UserDict.DictMixin,dict):'''Ratings类很像一个字典,但有一些额外特性:每个键的对应值都是该键的“分数”,所有键都根据它们的分数排名。对应值必须是可以比较的,同样,键则必须是可哈希的(即可以“绑”在分数上)所有关于映射的行为都如同预期一样,比如:>>>r = Ratings({"bob":30,"john":30})>>>len(r)2>>>r.has_key("paul"),"paul" in r(False,False)>>>r["john"] = 20r.update({"paul":20,"tom":10})>>>len(r)4>>>r.has_key("paul"),"paul" in r(True,True)>>>[r[key} for key in ["bob","paul","john","tom"]][30,20,20,10]>>>r.get("nobody"),r.get("nobody",0)(None,0)除了映射的接口,我们还提供了和排名相关的方法。r.rating(key)返回了某个键的排名,其中排名为0的是最低的分数(如果两个键的分数相同,则直接比较它们两者,“打破僵局”,较小的键排名更低):>>>[r.rating(key) for key in ["bob","paul","john","tom"]][3,2,1,0]getValueByRating(ranking)和getKeyByRating(ranking)对于给定的排名索引,分别返回分数和键:>>>[r.getValueByRating(rating) for rating in range(4)][10,20,20,30]>>>[r.getKeyByRating(rating) for rating in range(4)]['tom','john','paul','bob']一个重要的特性是keys()返回的键是以排名的升序排列的,而其他所有返回的相关的列表或迭代器都遵循这个顺序:>>> r.keys()['tom','john','paul','bob']>>>[key for key in r]['tom','john','paul','bob']>>> [key for key in r.iterkeys()]['tom','john','paul','bob']>>> r.values()[10,20,20,30]>>>[value for value in r.itervalues()][10,20,20,30]>>> r.items()[('tom',10),('john',20),('paul',20),('bob',30)]>>>[item for item in r.iteritems()][('tom',10),('john',20),('paul',20),('bob',30)]实例可以被修改(添加、改变和删除键-分数对应关系)而且实例的每个方法都反映了实例的当前状态:>>>r["tom"] = 100>>> r.items()[('john',20),('paul',20),('bob',30),('tom',100)]>>>del r["paul"]>>>r.items()[('john',20),('bob',30),('tom',100)]>>>r["paul"] = 25>>>r.items()[('john',20),('paul',25),('bob',30),('tom',100)]>>>r.clear()>>>r.items()[  ]''''''这个实现小心翼翼地混合了继承和托管,因此在尽量减少冗余代码的前提下获得了不错的性能,当然,同时也保证了语义的正确性。所有未被实现的映射方法都通过继承来获得,大多来自DictMixin,但关键的__getitem__来自 dict。'''def init(self,*args,**kwds):'''这个类就像dict一样被实例化'''dict.__init__(self,*args,**kwds)#self._rating是关键的辅助数据结构:一个所有(值,键)#的列表,并保有一种“自然的”排序状态self._rating =[ (v,k) for k,v in dict.iteritems(self)]self._rating.sort()def copy(self):'''提供一个完全相同但独立的拷贝'''return Ratings(self)def __setitem__(self,k,y):'''除了把主要任务委托给dict,我们还维护self._rating'''if k in self:del self._rating[self.rating(k)]dict.__setitem__(self,k,v)insort_left(self._rating,(v,k))def __delitem__(self,k):'''除了把主要任务委托给dict,我们还维护self._rating'''del self._rating[self.rating(k)]dict.__delitem__(self,k)'''显式地将某些方法委托给dict的对应方法,以免继承了DictMixin的较慢的(虽然功能正确)实现'''__len__ = dict.__len____contains__ = dict.__contains__has_key = __contains__'''在self._rating和self.keys()之间的关键的语义联系————DictMixin“免费”给了我们所有其他方法,虽然我们直接实现它们能够获得稍好一点的性能。'''def __iter__(self):for v,k in self._rating:yield kiterkeys = __iter__def keys(self):return list(self)'''三个和排名相关的方法'''def rating(self,key):item = self[key],keyi = bisect_left(self._rating,item)if item == self._rating[i]:return iraise LookupError,"item not found in rating"def getValueByRating(self,rating):return self._rating[rating][0]def getKeyByRating(self,rating):return self.rating[rating][1]
def _test():'''我们使用doctest来测试这个模块,模块名必须为rating.py,这样docstring中的示例才会有效'''import doctest,ratingdoctest.testmod(rating)
if __name__ == "__main__":_test()

讨论

在很多方面,字典都是很自然地被应用于存储键(比如,竞赛中参与者的名字)和“分数”(比如参与者获得的分数,或者参与者在拍卖中的出价)的对应关系的数据结构。如果我们希望在这些应用中使用字典,我们可能会希望以自然的顺序访间–即键对应的“分数”的升序——我们也希望能够迅速获得基于当前分数的排名(比如,参与者现在排在第三位,排在第二位的参与者的分数,等等)。

为了达到这个目的,本节给dict的子类增加了一些它本身完全不具备的功能(rating方法、getValueByRating、getKeyByRating),同时,最关键和巧妙的地方是,我们修改了keys方法和其他相关的方法,这样它们就能返回按照指定顺序排列的列表或者可选代对象(比如按照分数的升序排列,对于两个有同样分数的键,我们继续比较键本身)。大多数的文档都放在类的文档字符串中——保留文档和示例是很重要的,可以用Python 标准库的 doctest模块来提供单元测试的功能,以确保给出的例子是正确的。

关于这个实现的有趣之处是,它很关心消除冗余(即那些重复和令人厌烦的代码,很可能滋生 bug),但同时没有损害性能。Ratings 类同时从 dict 和 DictMixin 继承,并把后者排在基类列表的第一位,因此,除非明确地覆盖了基类的方法,Ratings 的方法基本来自于 DictMixin,如果它提供了的话。

Raymond Hettinger 的 DictMixin 类最初是发布在 Python Cookbook 在线版本中的一个例子,后来被吸收到了 Python2.3的标准库中。DictMixin 提供了各种映射的方法,除了__init__
、copy以及四个基本方法:__getitem__、__setitem__、__delitem__和 keys。如果需要的是一个映射类并且想要支持完整映射所具有的各种方法,可以从DictMixin派生子类,并且提供那些基本的方法(具体依赖于你的类的语义————比如,如果你的类有不可修改的实例,你无须提供属性设置方法__setitem__和__delitem__)。还可以添加一些可选的方法以提升性能,覆盖 DictMixin 所提供的原有方法。整个 DictMixin 的架构可以被看做是一个经典的模板方法设计模式(Template Method Design Pattern),它用一种混合的变体提供了广泛的适用性。

在本节的类中,从基类继承了__getitem__(准确地说,是从内建的dict类型继承),出于性能上的考虑,我们把能委托的都委托给了dict。我们必须自己实现基本的属性设置方法(__setitem__和__delitem__),因为除了委托给基类的方法,还需要维护一个数据结构 self._rating——这是一个列表,包含了许多(score,key)值对,此列表在标准库模块 bisect 的帮助下完成了排序。我们也重新实现了keys(在这个步骤中,还重新实现了__iter__,即 iterkeys,很明显,借助__iter__可以更容易地实现 keys)来利用self._rating 并按照我们需要的顺序返回键。最后,除了上面三个和排名有关的方法,我们又为__init__和 copy 添加了实现。

这个结果是一个很有趣的例子,它取得了简洁和清晰的平衡,并最大化地重用了 Python标准库的众多功能。如果你在应用程序中使用这个模块,测试结果可能会显示,本节的类从 DictMixin 继承来的方法的性能不是太让人满意,毕竞 DictMixin 的实现是基于必要的通用性的考虑。如果它的性能不能满足你的要求,可以自己提供一个实现来获取最高性能。假设有个Ratings类的实例r,你的应用程序需要对r.iteritems()的结果进行大量的循环处理,可以给类的主体部分增加这个方法的实现以获得更好的性能:

def iteritems(self):for v,k in self._rating:yield k,v

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901195.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

十四种逻辑器件综合对比——《器件手册--逻辑器件》

目录 逻辑器件 简述 按功能分类 按工艺分类 按电平分类 特殊功能逻辑器件 应用领域 详尽阐述 1 逻辑门 一、基本概念 二、主要类型 三、实现方式 四、应用领域 2 反相器 工作原理 基本功能 主要应用 常见类型 特点 未来发展趋势 3 锁存器 基本概念 工作原理 主要类型…

如何更改wsl2中的ubuntu默认安装位置

先前的一篇文章提到了如何更改wsl里面ubuntu的home目录,wsl装ubuntu的home目录在哪,如何更改home?_wsl安装的ubuntu在哪里-CSDN博客 这次是要更改wsl中ubuntu的安装目录,毕竟默认安装到c盘下会占用不少空间的。 从微软商店get后…

最近在工作中感受到了设计模式的重要性

之前了解设计模式:只是应付一下面试 在之前一年多的工作中也没遇到使用场景 最近在搭建验证环境的时候,才发现这玩意这么重要 首先是设计模式的使用场景一定是在很复杂繁琐的场景下进行的 之所以说是复杂/繁琐的场景,因为一些场景也许逻辑不难…

Python深度学习基础——卷积神经网络(CNN)(PyTorch)

CNN原理 从DNN到CNN 卷积层与汇聚 深度神经网络DNN中,相邻层的所有神经元之间都有连接,这叫全连接;卷积神经网络 CNN 中,新增了卷积层(Convolution)与汇聚(Pooling)。DNN 的全连接…

Linux 第三讲 --- 基础指令(三)

前言: 在前面我们已经讲了有十几个Linux的基础指令,今天我们再补充几个常用的基础指令,为后面的学习做准备 。 目录 前言: 一、两个与时间相关的指令 1.date指令 演示 : 时间戳 设置时间 2、cal指令 演示&#x…

基于SiamFC的红外目标跟踪

基于SiamFC的红外目标跟踪 1,背景与原理2,SiamFC跟踪方法概述2.1 核心思想2.2 算法优势3,基于SiamFC的红外跟踪代码详解3.1 网络定义与交叉相关模块3.2 SiamFC 跟踪器实现3.3 主程序:利用 OpenCV 实现视频跟踪4,总结与展望在红外监控、无人机防御以及低光照场景中,红外图…

Odoo 部署本地 把現時的excel計算表格部署上odoo 教程

要将现有的 Excel 计算表格部署到 Odoo 平台上,您可以按照以下步骤进行操作: 将 Excel 表格中的数据转移到 Odoo 模块中:首先,您需要将 Excel 表格中的数据导出为 CSV 格式,然后可以使用 Odoo 的数据导入功能将这些数据…

KWDB创作者计划—KWDB认知引擎:数据流动架构与时空感知计算的范式突破

引言:数据智能的第三范式 在数字化转型进入深水区的2025年,企业数据系统正面临三重悖论:数据规模指数级增长与实时决策需求之间的矛盾、多模态数据孤岛与业务连续性要求之间的冲突、静态存储范式与动态场景适配之间的鸿沟。KWDB(K…

C语言 数据结构 【栈】动态模拟实现

引言 动态模拟实现栈的各个接口 一、栈的概念与结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(LastInFirstOut…

Python itertools模块的groupby函数介绍

itertools.groupby 是 Python 标准库 itertools 模块中的一个函数,它的主要功能是对可迭代对象中相邻的相同元素进行分组。 itertools.groupby(iterable, keyNone) 函数 作用: 将连续的(相邻的)相同元素分组,返回 (…

Python实例题:使用Python生成分形图片

目录 Python实例题 题目 题目分析 需求理解 关键知识点 实现思路分析 代码实现 代码解释 mandelbrot 函数: 设置复平面区域和图像参数: 计算分形数据: 绘图展示: 运行思路 Python实例题 题目 使用Python生成分形图…

系统编程1(进程的概念与原理)

进程的概念与原理 计算机组成部分一般遵循冯诺依曼结构,也就是由控制器、运算器、存储器、输入设备、输出设备五个部分组成。 ⦁ 程序的编译 一般在编写出程序之后,并不能直接运行,而是需要把程序通过编译器进行编译,生成可执行…

《Vue Router实战教程》5.嵌套路由

欢迎观看《Vue Router 实战(第4版)》视频课程 嵌套路由 一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如: 通过 Vue Router,你可以使用嵌套路由配置…

使用Python解决Logistic方程

引言 在数学和计算机科学中,Logistic 方程是描述人口增长、传播过程等现象的一种常见模型。它通常用于表示一种有限资源下的增长过程,比如动物种群、疾病传播等。本文将带领大家通过 Python 实现 Logistic 方程的求解,帮助你更好地理解这一经典数学模型。 1.什么是 Logist…

《从零搭建Vue3项目实战》(AI辅助搭建Vue3+ElemntPlus后台管理项目)零基础入门系列第十二篇(完结篇):数据统计功能实现

🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 《从零搭建Vue3项目实战》(AI辅助…

研究嵌入式软件架构时遇到的初始化堆栈溢出问题

文章目录 2025年4月10日新增分析PC寄存器指针值排查问题map文件设计到的知识点1. **.bss 段(Block Started by Symbol)**2. **.data 段**3. **.text 段**4. **.heap 段**5. **.stack 段**6. **.rodata 段(只读数据段)**7. **.init…

软件架构评估两大法:ATAM 和 SAAM 的对比与实践

架构权衡分析方法(ATAM)和软件架构分析方法(SAAM)是软件架构评估领域中非常重要的两种方法,以下为你详细介绍: 一、架构权衡分析方法(ATAM) 1.背景与起源:ATAM 是由卡耐…

Python爬虫-爬取全球股市涨跌幅和涨跌额数据

前言 本文是该专栏的第52篇,后面会持续分享python爬虫干货知识,记得关注。 本文中,笔者将基于Python爬虫,实现批量采集全球股市行情(亚洲,美洲,欧非,其他等)的各股市“涨跌幅”以及“涨跌额”数据。 具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。…

电流互感器的两相星形接线的建模与仿真

微♥“电击小子程高兴的MATLAB小屋”获取巨额优惠 1.模型简介 本仿真模型基于MATLAB/Simulink(版本MATLAB 2016Rb)软件。建议采用matlab2016 Rb及以上版本打开。(若需要其他版本可联系代为转换) 2.仿真模型 3.仿真结果 3.1一次…

详解 kotlin 相对 Java 特有的关键字及使用

文章目录 1. val 和 var2. fun3. when4. is 和 !is5. lateinit6. by7. reified8. companion 本文首发地址:https://h89.cn/archives/366.html 最新更新地址:https://gitee.com/chenjim/chenjimblog Kotlin 在兼容Java的基础上,引入了许多特有…