6. Python早期设计与开发:从ABC到Python

原文by Guido van Rossum 2009-02-03 翻译by kant


1. 缩进风格

Python最初的、也是最主要的影响来自ABC,一门由 CWI 设计于上世纪80年代初的编程语言(译注:见之前的博文)。ABC最初的目标是替代BASIC,成为一门教学语言,并成为针对个人用户的编程语言与编程环境。ABC的设计,立足于对用户编程行为的分析,之后根据用户测试的情况,发布了几个迭代版本。当时,我主要负责与集成编程环境(IDE)的对接。

Python对缩进的使用,就是直接借鉴于ABC。不过,使用缩进并不是ABC的发明——经由 Donald Knuth 的倡导,缩进在那时已经是一种众所周知的编程风格了(occam语言也使用了缩进风格)。ABC团队创新的地方,是用冒号来区分缩进逻辑块的前导语句。最初,ABC也没有引入冒号,结果在用户测试中发现,编程初学者很难区分各种缩进。引入冒号之后,整个结构就清楚多了:冒号好像把前导语句与其后的逻辑块完美组合在了一起。


2. 主要数据类型

Python的主要数据类型也都来自ABC,只是作了一些调整。ABC中的列表实际上是多重集,通过B树结构,保持列表中的数据是有序的。而ABC中的表,键值也是有序的。我认为这两种数据结构都不适合表现一些非常常用的数据,比如从文件中读取的文本行。(在ABC中,读取文本行必须使用表结构,并把行数作为键值,但这样的话,插入和删除行就会变得很复杂。)因此,我把列表改为无序的,并可以自由插入和删除,从而方便用户控制其序列。有需要时,也可以调用方法进行排序。

同时,我也用哈希表替代了ABC中的有序表。相对于B树来说,我认为哈希表更快,也更容易实现。理论上说,B树结构中的许多操作,在空间和时间复杂度上都是线性的,但在实际应用中,实现起来很困难,因为B树的算法本身比较复杂。而当表的规模比较小时,B树的效率更低。

Python 元组的封装与拆包操作其实是从ABC照搬过来的。不过元组内部实际上就是一个数组,因此我增加了索引和切片操作。

因为给元组增加了类似于数组的接口,我不得不考虑空元组或只有一个元素的元组要怎么表达的问题。作为从ABC借鉴过来的原则之一:任何一种数据类型,在打印、或者转换为字符串的时候,都应该让解析器能正常解析。同时我又得把只有一个元素的元组和带括号的参数区分开来。因此只得采取一种丑陋但务实的方式:如果元组只有一个元素,需要在元素后加一个逗号,如果是空元组,就用“()”表示。事实上,元组一般是不需要括号的,只有在空元组的时候必须用括号——我感觉如果用完全的“空(nothing)”表示空元组,可能很容易与大家的其它语法错误混淆起来。

Python 中的字符串和 ABC 中的字符串一样,都是不可变类型,但用了不同的符号,索引也改为从0开始。主要是因为 Python 中已经有三种可索引类型:列表、元组和字符串,它们的索引方式还是要统一为好,这样,一些核心方法才能保持一致,比如获取长度(len(s))、通过索引取值(s[i])、切片(s[i:j]),以及迭代(for i in s)等。


3. 数字类型

Python 和 ABC 最大的不同在数字类型。ABC 在运行时有两种数字类型,一种是精确数字,即任意精度有理数,一种是约略数字,即指定范围的二进制浮点数。这个有理数实在是槽点满满。(吐槽:有次我用ABC计算要交的税,公式很简单,但几个数字就运算了很久。研究了下发现,它居然算到了小数点后几千位,最后的结果却只需要小数点后一两位。)因此,在 Python 中,我使用了传统的数字模型,即系统位数的整型,以及系统位数的二进制浮点型,底层实现上,直接用的 C 语言中的长整数(long)和双精度浮点数(double)。

考虑到任意精度数字还是有很多重要的应用场景,我在 Python 中增加了一种大数类型,叫做长整型(long)。数年前我给 ABC 写过类似的实现(ABC最初的实现,也是我在ABC团队做的第一件事之一,底层用的是十进制表示方式),因此,这里就直接使用了现成的代码。

虽然我在 Python 中增加了大数类型,但还是应该强调,大多数场景中并不需要用到它。从我自己及我在CWI的同事所写的 Python 代码来看,大多数程序的运算时间中,很大部分都是整数运算,最常见的是计算内存索引。因此,我想,绝大多数情况下应该使用系统位数整型,大数类型只在少数情况下会用到,比如严谨的“数学”运算,或者以“分”为单位来计算美国国债的时候。


发表评论

评论列表,共 0 条评论