Python数学函数,python常用的魔法函数
本文给大家带来一些python的知识,包括“__missing__()”函数的相关问题。让我们来看看这个神奇的功能,希望对你有所帮助。
推荐:python学习教程
00-1010从普通字典中取值时,可能会出现键不存在的情况:
dd={name:PythonCat}
Dd.get(age) #结果:无
Dd.get(年龄,18) #结果:18
Dd[age] #报告的密钥错误
Dd。__getitem__(age) #相当于dd[age]
对于get()方法,它有一个返回值,第二个参数可以在键不存在时作为返回内容传入,所以可以接受。但是,其他两种写法都会出错。
为了解决后两种写法的问题,可以使用__missing__()的魔法。
现在,假设我们有一个请求:从字典中取一个键对应的值,如果有值就返回值,如果没有值就插入这个键,并给它一个默认值(比如空列表)。
如果使用原生dict,就不太容易实现。然而,Python提供了一个非常有用的扩展类集合。
如图所示,当检索到不存在的键时,不会再报告KeyError,而是默认存储在字典中。
为什么defaultdict可以这样做?
原因是defaultdict在继承了内置类型dict之后,还定义了一个__missing__()方法。__getitem__取不存在的值时,会调用传入参数的工厂函数(上面的例子是调用list()创建空列表)。
作为最典型的例子,defaultdict在文档注释中写道:
简而言之,__missing__()的主要作用就是由__getitem__在缺失 key 时调用,从而避免出现 KeyError。
另一个典型的使用示例是集合。Counter,也是dict的子类。当获取未被计数的密钥时,它返回计数0:
00-1010从上面可以看出__getitem__()取不到值时会调用__missing__()。然而,我不经意间发现了一个细节:__getitem__()在取不到值时,并不一定会调用__missing__()。.
这是因为它不是内置类型的必要属性,也没有在字典基类中预定义。
如果直接从dict type中取属性值,会报错该属性不存在:属性错误: type object object 没有属性 _ _ missing _ _ 。
检查dir()并发现该属性不存在:
如果你看看dict的父类,也就是object,你会发现同样的结果。
这是怎么回事?为什么dict和object中没有__missing__属性?
但是,参考最新的官方文档,object中明确包含了该属性:
来源:https://docs.python.org/3/reference/datamodel.html? highlight=_ _ missing _ _ # object。__缺少_ _
也就是说,理论上,__missing__会在object类中预定义,它的文档也证明了这一点,但实际上并没有定义!文件和现实有偏差!
这样,当dict的子类(比如defaultdict和Counter)定义__missing__时,这个神奇的方法实际上只属于这个子类,也就是它是一个诞生于子类中的魔术方法!.
据此,我有一个不成熟的猜测:__getitem__()会在调用之前判断当前对象是否是dict的子类,是否有__missing__()的(如果父类也有这个方法,就不先判断,直接调用)。
我在交流群里说了这个猜想,有同学很快在CPython源代码里找到了验证:
这很有趣。放眼整个在内置类型的子类上才存在的魔术方法,,的Python世界恐怕很难找到第二种情况。
我突然有一种联想:这种难以捉摸的__失踪_ _()就像一个
个擅长玩“大变活人”的魔术师,先让观众在外面透过玻璃看到他(即官方文档),然而揭开门时,他并不在里面(即内置类型),再变换一下道具,他又完好无损就出现了(即 dict 的子类)。
3、被施魔法的__missing__()
__missing__() 的神奇之处,除了它本身会变“魔术”之外,它还需要一股强大的“魔法”才能驱动。在上篇文章中,我发现原生的魔术方法间相互独立,它们在 C 语言界面可能有相同的核心逻辑,但是在 Python 语言界面,却并不存在着调用关系:
魔术方法的这种“老死不相往来”的表现,违背了一般的代码复用原则,也是导致内置类型的子类会出现某些奇怪表现的原因。
官方 Python 宁肯提供新的 UserString、UserList、UserDict 子类,也不愿意复用魔术方法,唯一合理的解释似乎是令魔术方法相互调用的代价太大。
但是,对于特例__missing__(),Python 却不得不妥协,不得不付出这种代价!
__missing__() 是魔术方法的“二等公民”,它没有独立的调用入口,只能被动地由 __getitem__() 调用,即__missing__() 依赖于__getitem__()。
不同于那些“一等公民”,例如 __init__()、__enter__()、__len__()、__eq__() 等等,它们要么是在对象生命周期或执行过程的某个节点被触发,要么由某个内置函数或操作符触发,这些都是相对独立的事件,无所依赖。
__missing__() 依赖于__getitem__(),才能实现方法调用;而 __getitem__() 也要依赖 __missing__(),才能实现完整功能。
为了实现这一点,__getitem__()在解释器代码中开了个后门,从 C 语言界面折返回 Python 界面,去调用那个名为“__missing__”的特定方法。
而这就是真正的“魔法”了,目前为止,__missing__()似乎是唯一一个享受了此等待遇的魔术方法!
4、小结
Python 的字典提供了两种取值的内置方法,即__getitem__() 和 get(),当取值不存在时,它们的处理策略是不一样的:前者会报错KeyError
,而后者会返回 None。为什么 Python 要提供两个不同的方法呢?或者应该问,为什么 Python 要令这两个方法做出不一样的处理呢?
这可能有一个很复杂(也可能是很简单)的解释,本文暂不深究了。
不过有一点是可以确定的:即原生 dict 类型简单粗暴地抛KeyError
的做法有所不足。
为了让字典类型有更强大的表现(或者说让__getitem__()作出 get() 那样的表现),Python 让字典的子类可以定义__missing__(),供__getitem__()查找调用。
本文梳理了__missing__()的实现原理,从而揭示出它并非是一个毫不起眼的存在,恰恰相反,它是唯一一个打破了魔术方法间壁垒,支持被其它魔术方法调用的特例!
Python 为了维持魔术方法的独立性,不惜煞费苦心地引入了 UserString、UserList、UserDict 这些派生类,但是对于 __missing__(),它却选择了妥协。
推荐学习:python教程以上就是Python魔法函数学习之__missing__的详细内容,更多请关注盛行IT软件开发工作室其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。