描述符协议及Python黑魔法
描述符协议及Python黑魔法,和其他典型的程序员一样,我做的第一件事就是把那段代码复制粘贴到终端中,即使我知道预期的结果会如何。我的回应很简单:
去年夏天毕业后,我用Python2和3编写过非常多的代码。这段代码似乎我应该理解的很好,实则不然,所以这篇文章就会试图解决这个问题。我的灵感来源于JuliaEvans,以及她分享所学知识的活动,虽然她的理解可能并不到位。
这篇文章假设你已经对Python和OOP有个基础的认识。为了更好地了解Python中的OOP,我推荐你看LeonardoGiordani的系列文章,它从基础的概念到Python类内部的实现都有很好的说明(他也编写了基于Python2.x版本的文章,但是我并没有仔细阅读过)。
所以,黑魔法到底是什么?
我的第一反应就是检查比较行为的本身。”==”相当于对象中的__eq__方法用来检测是否相等,而”is”则是检查标识的关键字,所以那些对象在内存中不可能一样!
果真如预期的一样!Python2中的内存地址(使用id来表明)是不一样的,所以identity检测失败,而Python3中却不如此。但是为什么一个显示”unboundmethod“而另一个显示”function”呢?这些对象在内部是如何存储的呢?在大多数情况下,Python使用字典,即使用__dict__来访问保存在本地的变量,或者对象的命名空间(注意并不是所有对象都有__dict__,这是另一个故事了)。所以让我们看下b在A中是如何的:
啊哈?在Python2中它是一种instancemethod而在3中却是一个函数,但是当我们使用type去检查__dict__中b的类型时发现都是functions?这是怎么回事?其实这是由描述符协议的设计造成的,它定义了通过一系列属性访问对象中数据时如何表现。在Python2中,协议根据函数对象是如何被访问来区分type类型。在文档中,RaymondHettinger解释如下:
在Python3中,bound和Unbound之间的区别消失了,但奇怪的是,Python3的文档并没有更新,所以我还不能清楚地了解底部是如何实现的。相同的代码也有不同的输出:
就像文档中解释的那样,bount和unbound方法都是由相同的C代码来实现,区别仅在于它们的im_self属性,unbound的方法是NULL。所以我猜测instancemethod会在运行时动态地创建出新的函数对象,在Python2中不会区分bound和unbound,而在3中只有bound时才会初始化,因为unbound方法根本不存在。这是很有意义的,意味着你在访问函数时必须去执行它。
如果事实真是这样,那么调用A的一个实例中的b方法时永远会返回一个不同的对象,而不会区分我们的Python运行时环境,因为它们都是bound类型的。
所以在Python3中A.bisA.b,而在2中却不成立的原因就是bound/unbound的区分。看起来描述符协议就是这个巫术的始作俑者!黑魔法往往是我们尚不清楚的技术。
如果你对此有更深的理解和体会,欢迎联系我~
更新(4/26/16):JakeVanderPlas回复了我的推特,并引用2009年Guido的一篇文章来解释这个行为,很明显,bound/unbound仅仅是为了实现”first-classeverything”这一目标,在Python3中去除unbound方法仅仅是这一想法的更深层次的表达。
更新2(4/29/16):今天我收到了ToddJennings的邮件,他指出了一个Python3文档过期的Bug,但是这个bug仍然被标记为等待的状态。
Python培训、Python培训班、Python培训机构,就选光环大数据!
还不够过瘾?想学习更多?点击 http://hadoop.aura.cn/python/ 进行Python学习!
大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请专业的大数据领域知名讲师,确保教学的整体质量与教学水准。讲师团及时掌握时代潮流技术,将前沿技能融入教学中,确保学生所学知识顺应时代所需。通过深入浅出、通俗易懂的教学方式,指导学生更快的掌握技能知识,成就上万个高薪就业学子。 更多问题咨询,欢迎点击------>>>>在线客服!