当前位置: 首页 > 工具软件 > Sprint.js > 使用案例 >

Python Sprint 报告

葛宏爽
2023-12-01

为了便于参考,这里是关于本次 sprint[1] 的 wiki 页面和 py3k 的wiki页面

Python 3000 Sprint 的成果

我将从本次 sprint 的 Py3k 部分的成果开始,因为我是最直接地参与了。

热身

在本次 sprint 的前几周,我已经对解释器做了几处深层次的修改,比如将 classic class[2]完全去掉,并且去掉了绝大多数的 has_key()。这造成了一些严重的后果,在 sprint 开始的时候,6个左右的单元测试失败了。其中三个失败被几个 sprinter 进行攻克并很快修复了。

作为另一场热身练习,Alex Martelli 和我解决了 __hash__ 重载的问题。这个问题很微妙,在这里很难解释得很清楚。这个问题是:object.__hash__ 应该存在,然而理想地象 list.__hash__ 不应该存在。解决的方法是: 在元类中,只要一个类覆盖了比较方法但没有定义 __hash__ ,则将 __hash__ 设为 None。我们完成得很快,比效实际完成它所花费的时间,也许我们应该花更多的时间去阅读旧的代码,努力理解它们,然后讨论各种可行的替代方法再去修复这个问题。

在这一时刻(第一天晚些时候)在 py3k 分支中的所有的单元测试都通过了。这是一个非常重要的里程碑:我们现在能够相信任何新的测试失败都是由于最近的修改带进来的,同时也强调了程序员应该在提交修改之前应该让所有的测试都通过。

Anna Ravenscroft 仔细检查了标准库,查找在哪里 file() 被调用以构造一个文件对象( file将被未来所证明,并且因此被推荐使用),但实际上却是调用了 open() 而不是 file()。在仔细检查了从 'a' 开头到 'g' 开头的模块之后,却没有发现一处 file(),她问我是不是和她开了一个残酷的玩笑。不是,只是因为所有让人厌恶的调用发生在字母表相对靠后的地方!(我想知道是不是也有其他人对 2.5 的库也做过同样的事情,并且在修复了前一半字母表后就放弃了?)

Int/Long 的统一

Martin von Löwis 决定解决整数和长整数统一的问题。他在一个独立的分支中做这件事,从软件开发的角度来说这当然是一件好事,但却使他得到了一些不必要的关注,那些不在 Python 3000 邮件列表中但却是在 python 提交列表中的核心开发人员,他们开始批评 Martin 的尚未完成的工作,因为他们不理解这个计划或它的前因后果。

在我写这个的时候,Martin 的工作仍然还没有完成。一个统一的整数对象的分配(在这一点上,它本质上就是一个 Python 2.5 的长整数,也就是一个任意精度的整数)需要花费两倍于一个 Python 2.5 "短" 整数(它只能保持一个C的长整数,也就是根据不同的系统是32或64位)的时间。Martin 不确定如何能把速度再提高。 Pystone 性能下降了大约 10%,不算太坏。还可以看一下 Martin 的完整报告

对比较进行彻底改造

Neal Norwitz 暂时还在继续着一个项目,这个项目在这个 sprint 开始之前他就已经着手了:清除最后残留的 coerce()。他几乎就要完成了,但接着遇到了一个困难:有一个对 PyNumber_CoerceEx() 的调用,它在很深层的比较的实现中,一旦去掉,它就会引起所有东西都崩溃。所以他提交了到那一刻的工作(留下了那个讨厌的调用),并且把接力棒传给了我。看着这个问题,我意识到解决它的唯一的方法将是需要实现一个比较的修订版,也就是我已经在 Py3k 中所计划的。

所以最终我花费了至少两天的时间,在 Alex 的帮助下,重新实现了比较,使它们贴近我对 Python 3000 中的比较的想法。这样将制造出一个真正的蠕虫罐头!(原文:This turned out to be a real con of worms!)这个计划有两部分:(a)没有缺省的混合类型顺序,所以象 'a'<1 将引发一个 TypeError 的异常(但 'a'==1 应当返回 False);(b)对于富比较(rich comparison[3])不再后退到 __cmp__(译注:即当富比较找不到时,不再自动调用__cmp__) 。

开始的时候我实现了对这些规则的一个超严格解析,它删除了在进行富比较时需要 __cmp__ 的后退(译注:即不再调用 __cmp__)。可是一旦它被编译,甚至都无法启动,结果是由于在 site.py 中的一些代码被破坏了。查出来是由于整数和长整数根本就没有实现富比较!这个问题很快被修复了,现在我们至少可以启动解释器了。但是运行测试用例时总是由于段错误而最终停止。后来我发现这是由于一个在字节码编译器中对字典查找的失败的错误检查造成的(第二天被 Jeremy 很快修复了),它是被一个不再有合适的比较的代码对象(code object)所触发的。从代码对象中去掉了所有的比较代码,然后让它默认地使用缺省的比较(和hash)实现,这样就可以很好的阻止编译器产生错误。

在这一时刻,我们还有着将近70个错误单元测试。我花费了大约一天的时间来一个个的修复它们。在这个过程中我还算及时地意识到,如果两个对象都不知道如何来比较自身和其它对象,对于==和!=,我们不应该返回失败,而是应该返回缺省的比较。再后来,我决定,由于在库和测试用例中需要去掉cmp()用法的地方太多,这样我不得不妥协:当cmp没有找到一个 tp_compare 实现时,它后退到使用 tp_richcompare 实现。但(并且这仍然是一种从2.5的大大的脱离(原文:and this is still a big departure from 2.5))并非从相反的方向(译注:指后退的方向)。

越来越多的单元测试慢慢地但确信地被修复了。我在仅有4个失败的测试的检查点(checkpoint)时提交了代码。其中有两个是希望通过值来比较代码对象,我最终又实现了一遍(但没有调整代码对象!)。最后两个失败的测试需要Tim Peters的会诊:datetime 有一些十分令人费解的代码用来避免碰上缺省的排序(ordering),这在 Py3k 中不再是一个问题,所以就被去掉了,最后剩下的是 test_mutants.py。在 Tim 解释了为什么它会存在并且如何修复它之后,用它找到了一个引用计数的错误!这就是它的工作,但有趣的是同样的引用计数错误也存在于 2.5 中并且没有被发现,因为在 2.5 中 test_mutants 只实验了三方比较但没有实验富比较(并且 2.5 的字典实现都是分开的!)。

这很有趣(以某种极端的奇客(geek)的做法:)但也意味着不能进行原来我真正想做的项目:新 I/O 库。有几个人(特别是 Charles Merriam 和 Hasan Diwan)看过设计问题但是没有做出一些具体的东西来。

其它的项目

Hasan Diwan 承担着将 find() 的调用转换为 index() 的工作。这受到了来自 python-3000 列表的相当多的批评。其中一些批评是正确的,因为 Hasan 还不了解 partition(),这是一个在许多场合下比 index() 还要好的查找子串的API。在这个时候,Hasan 正在制作一个修订的补丁,用来合并这个想法。我仍然认为 find() 是一个危险的 API,我已经看到过许多的问题产生都是由于错误地解释了用来表示失败的负数返回值。

其它一些成果:John Reese 和 Jaques Frechet 去掉了 reduce()。整个标准库只有少数的使用被找到。他们接着继续去除在idlelib中剩下的的has_key()的使用(因为idlelib没有单元测试,而我上周在去掉has_key()时忘了这些)。(IDLE仍然不能工作,但是问题看上去简单多了,它使用了旧式的相对导入,而它们在 py3k 中不能使用)。

Neal 也在对付另一个项目:重写 xrange() 以支持长整数。这将对 Python 2.6 也有好处。他作了两个版本:一个是用 C,一个是用 Python 。有一个公开的讨论关于是否值得用 C 来实现,特别是 Python 的代码对于理解和维护来说这么短和简单。

Thomas Wouters 也在清理分片。不,不要担心,分片的语法仍然保留,只是对分片操作进行各种各样的“优化”,清除那么帮助不大,反而是API的阻碍的东西,使API更简单。这项工作在另一个分支中被完成,并且 Thomas 还写了一个非常好的报告

Brett Cannon(同 Jiwon Seo一起)编写了 PEP 362,规范了函数签名对象(Function Signature Object)(可能在 Python 2.6中首次发现这种方式);Brett 继续编写了一个原型实现,而 Jiwon 则继续他的项目,完成 PEP 3102,只允许关键字参数。Brett 还开始从库中清除倒单引号[4](有利于repr()),他只发现了很少的几处,所以这是一件很快的工作!

Brian Holmes 用 C 编写了一个补丁用来将 zip 实现为一个迭代器(iterator)。

Python 2.5/2.6 Sprint 的成果

这里我不得不推后了一些其它人发给我的片段。

Thomas Wouters 花掉了这个 sprint 的第一天的时间用在一个针对 unicode 的 bigmem 测试上,测试大于 1<<31 个字符的 unicode 对象(不是字节,是字节的2和4倍,测试了两种 unicode 宽度)。这不是一个十分全面的测试(忽略了编码和解码),但是乞今还没有发现问题。现存的对于字节字符串、元组(tuple)和列表(list)的 bigmem 的测试也没有发现问题。

Neal Norwitz 花了一天的时间在 Python 2.5 问题处理方法上(除了上述他的 xrange 工作之外)。

Brett Cannon 起草了关于问题报告和补丁提交的开发者指南。

 


 

[1]sprint可以理解为在短时间内,聚集一些开发人员,一起解决一些问题的活动,可以理解为“编程冲刺”

[2]在 python 2.2以后引入了 new style class,因此为了之原来的对象体系相区别,就把以前的对象体系称之为classic class。具体的可以参见 http://www.python.org/download/releases/2.2.3/descrintro/

[3]富比较(rich comparison)是指具体的比较处理,如 >, <,这些比较处理当应用于对象时,可以通过在类中定义特殊的方法,__gt__(>), __lt__(<)等来实现,它们叫 rich comparison。更具体的可以参考 http://docs.python.org/ref/customization.html 中的关于特殊操作符重载的函数说明。

[4]倒单引号的作用同repr()是一样的。但不如repr()更清晰。

原文链接 http://www.artima.com/weblogs/viewpost.jsp?thread=173453

 类似资料: