中译版的 SICP 好难读啊

我最早是在上高中时,从王垠的网站上知道了 Scheme 这门编程语言,后来洪峰的一些文章也提到了不少 Scheme 的功能。那时我比较迷恋 Scheme,一方面因为我从来没有接触过函数式编程语言,Scheme 这种用小括号堆砌出来的代码,比起过程式编程语言来说新奇了许多;另一方面也有 LISP 光环带来的效应。所以当我得知了有一本书,名为 Structure and Interpretation of Computer Programs,中文名为《计算机程序的构造和解释》,堪称 Scheme 语言的“圣经”,并且是麻省理工学院计算机系的初等课程教材后,我就一直像一窥这本书的风貌。

那时我似乎就已经听说这本书在网络上有全文可以阅读,但一来我没有自己的计算机,使用网络也不方便;二来我当时的英文水平来阅读这类科技书籍还有些不足,所以我一直没敢深入接触这本书,转攻字数更少的 R5RS——一共 50 页,描述了 Scheme 语言的方方面面,我把它打印了下来,装钉起来慢慢的查字典一个单词一个单词的啃。当时我的感觉是当我看到有不确定含义的词语时,查字典,用笔标记上含义,等积攒了几句话后,整体读下来还是一头雾水。文章的含义都没有吃透,更别提 Scheme 语言本身了。所以这项工作我也没有坚持很久,最后只是在蹲厕所的时候拿上看两眼里面的程序,揣摩语言的含义罢了。

所以当我听说,SICP 这本书被裘宗燕翻译了之后,我心里非常激动。有一次我去一家计算机书籍比较多的小书店,找不到这本书,于是问售货员,被告知这本书因为太冷门,没有存货,不过可以预定。我当然选择预定啦。不久后家里接到书店的电话通知,说是有货了,我于是在一个周末和朋友去把书买了回来。这已经是我上大学后的事情了。

这本书到手后,我阅读后得到一个结论——SICP 果然非常难读。因为我除了一些注释中的小故事外,其它的都看的云里雾里。当时我也没有时间,于是只把这本书当作休闲读物,磨损我自己的脑力。

我出国的时候没有带任何计算机方面的书籍或文章,出国后我还比较想念几本书,其中就包括 SICP。我还特地请母亲从车库里找出这本书,让回国的同学帮我带过来。后来使用英语更多了,阅读一些科技文章也不是那么困难了。于是也渐渐的从网站上看了原版的 SICP。这时我又觉得不对劲了。按照我的经验,这本书开始时我就读的云里雾里,那么就应该从开始往后读啊,可怎么读着读着就觉得这么无聊呢?仔细一看原来这些知识我都知道了啊,于是我就往后翻,翻了很大一部分之后还是觉得简单。当然,中间夹杂了一些数学定理什么的,还有一些题目什么的确实需要一些时间思考,但主题部分绝对不是什么艰深晦涩的东西,那为什么读中文版给我的压力这么大呢?

我仔细的看中文的译文,发现可以用这么一句话来形容:每个字每个词都认识,但练成一句话就是不懂什么意思。或许这话夸张了点,但却给了我类似的感觉。或许文字还算流畅,但就是无法让我理解 Scheme 这门语言。一种说不出的感觉。反之,看了英文原版之后,很多东西都清晰明了了。中国人讲究翻译的境界是信达雅,在这里我觉得差距就在雅上。有些词语是严格翻译过来的,从计算机角度上就非常晦涩。这搞的我都想买一本原版的书了。后来看了亚马逊上的售价,考虑再三我放弃了。这类书我更希望能弄到硬皮本的,也不负它 Wizard Book 的名号了,可惜上百加元的书在我看来完全不可接受。普通版本的要 40 多,我因为有了电子版的全文,因此觉得这也有些不划算。

我之前有时间也翻译过一些东西,当然还没到技术文档的水平,只是一些故事,比如 Python 语言的创始人 Guido van Rossum 写的 Python 历史的一系列文章。今天看来,翻译的相当稚嫩。当然每个词语都翻译好了,句子也算通顺,但整体读下来就是觉得有那么些别扭。因为我不是专业做翻译工作的,那时只是在课余时间来翻译一部分,因此翻译完了就完了,从来没有做过事后调整工作,导致文章仅仅是中学生作文水平的可读性罢了,我自己觉得作为业余历史性质的文献也算是勉强合格了。所以我觉得 SICP 这本中译版应该还有改进的空间。

当然我不是否认老裘的工作。人们普遍认为 SICP 难翻,裘宗燕的译文成果,无论怎么样,也算是里程碑式的成就了。我还买过裘宗燕的另一本书,是 C++ 语言的创始人写的一本官方的教程,我现在对它唯一的印象就是很厚重了,书名我也记不清了。当然那本书我也没有读多少,现在也想不起来译文的质量如何了。说起来我最喜欢的一本中译计算机程序语言类书籍是 Learning Perl,那本书实在是让我觉得妙趣横生、手不释卷。书的厚度也非常优秀,作为入门书籍既精炼、清晰、明确,又有足够的深度,文字也非常吸引人。要不是现在 Perl 不再流行了,我一定随时带着它。

谷歌翻译辅助系统好棒

今天早上看Google Reader的时候,从Google黑板报上看到了“谷歌翻译辅助系统”(Google translate toolkit)发布的消息。开始的时候我没在意,只是顺手点了一下产品的链接,继续看其它文章了。等进去一看,却让我吃惊的有点合不拢嘴──这正式我想了很久的东西了。

我过去曾经翻译过或多或少的英文计算机相关的文章,一来锻炼英文,二来也算“造福大众”。在今年2月左右,我翻译了几篇Guido van Rossum写的《Python历史》。那时Guido刚刚开始写,我本来想的好好的,Guido出一篇,我就翻译一篇。不过翻译了几篇后我的进度就再也跟不上了。最后的一次是Guido似乎那一阵子比较闲,放出一大长篇后,没几天又放出一大长篇。Guido的英文风格让我看来有点过于复杂的感觉,不知道是不是因为他母语是荷兰语的感觉,翻译他的文字比翻译标准英语母语的人(比如Andy Hertzfeld)要吃力。

后来我曾经仔细的想过这个问题,发现我在翻译中最大的困难是没有好的工具。我的翻译方法是:先把要翻译的英文存成文本文件,在emacs里面一段一段的翻。经常在写下措辞了很久的中文翻译后,要花很长时间回去找下一句英文。我也不是那种做一件事能非常专注的人,经常在回头找英文的时候就走神了。因此,让我做少量的几篇翻译我大概可以胜任,但在一段时间内连续的翻译就不行了。

我曾经想找这么一个工具:把一篇英文文章交给它后,它会分析这篇文章,一句一句的把文章分开,并在对应的地方留出我填写中文的空间。因此我可以方便的把注意力集中在一句英文上,并把想好的中文句子填上,然后进行下一句。我从网上简略的搜索过,没有找到免费的相关产品。后来我觉得用Django或Rails做一个这种工具似乎是可行的,可惜一直没有找出时间来。这次又让Google领先了。下面是我的截图:

谷歌翻译辅助系统就是一个我描述的系统。左边是英文原文,右边是用Google Translate自动翻译的中文译文。右侧有一个悬浮窗口,显式当前翻译的句子,同时左边被翻译的这句会被高亮标示出来。当我们翻译完一句后,可以点悬浮窗口的Previous和Next跳到前一句或者后一句,这样的东西对不当专业的翻译人员的外语爱好者来说已经相当足够了。

另外,谷歌翻译辅助系统又加上了分享(我没试过,我猜可能会是多人同步翻译,如果个Google Wave结合起来,应该会更爽)、翻译进度百分比、单词统计这样的功能,更是锦上添花。而且它还支持Wikipedia、Knol之类的在线wiki,我虽然没尝试过,不过我想大概是可以分析它们的页面语法,也许会通过API在系统中直接完成编辑并上传也说不定。

目前发现的唯一的缺点就是还没找到修改文件名的地方。我在上传一篇文章的时候,以为可以像Google Docs那样点一下文件名就可以改动,没想到点了半天连点反应都没有。如果真的有这个功能的话,我觉得大概藏的太深了。

翻译Python历史:Python对动态类型的使用

This post a a Chinese translation of Guido van Rossums‘s article “Python’s Use of Dynamic Typing” on his blog named “The History of Python“.

原文地址:http://python-history.blogspot.com/2009/02/pythons-use-of-dynamic-typing.html

ABC和Python间一项重要的区别是类型系统的总体特点不同。ABC是静态类型语言,意味着ABC编译器分析程序中使用的类型并判断它们被正确的使用。如果不是,程序会被拒绝并无法运行。不像今天多数静态类型语言那样,ABC使用类型推断(像Haskell那样)而不是像你在C之类的语言中看到的显式的类型声明那样。相反的,Python是动态类型语言。Python编译器高兴的对程序中类型的使用不感兴趣,所有的类型检查都在运行的时候进行。

尽管这样看上去对于ABC是一种很大的远离,但它并不如你想象的那样不同。不像其它静态类型语言,ABC不是(不曾是?它在今天确实已经是纯历史了:-))仅仅依赖于静态类型检查来确保程序不崩溃,当所有的操作执行时,它有运行期的库来为它们再次检查参数类型。这样做是因为编译器健全的类型检查算法的一部分在最初的语言原型实现中并没有被实现。运行期的库在调式的时候同样有用,因为显式的运行期类型检查可以产生漂亮的错误信息(指向实现团队),而不是解释器毫不检查参数时就盲目的运行而引起的core dump。

然而,ABC在静态类型检查外同时拥有运行期类型检查的最重要的原因是它是交互式的。在交互会话时,用户输入的ABC指令和定义在输入完成后就马上执行。在交互会话时,有可能会生成一个数字变量,删除它,然后再重新把它创建(换句话说,生成另一个有相同值的变量)成字符串。在一个单一子程序中,让一个相同的变量名先成为数字然后成为字符串是一个静态类型错误,但在交互会话中强制在不同的输入的指令里做这种类型检查并不合理,因为偶然创建的名为x的数字变量后边永远不能再用x用作其它不同类型的变量了!所以作为妥协,ABC对全局变量用了动态类型检查,但对局部变量用静态类型检查。为了简化实现,局部变量也是动态检查的。

因此,从ABC的类型检查实现方案到Python的方案只有一小步──Python简单的完全去掉了编译期类型检查。这完全符合Python的”切角”哲学,原因是如此精简实现不会引起安全问题,因为所有类型错误都在运行期中他们引起Python解释器发生故障前被捕获。

然而,一旦你决定了使用动态类型就没有回头路了。ABC的内建操作小心设计以便参数的类型可以从操作中推导出来。例如,在表达式”x^y”里编译器会推导出变量x和y是字符串,表达式的结果也是。在Python中,这样的推导基本上不能实现。例如,表达式”x+y”可能是字符串连接、数字相加、或者执行用户重载的操作。

翻译Python历史:早期语言的设计与开发

This post a a Chinese translation of Guido van Rossums’s article “Early Language Design and Development” on his blog named “The History of Python”.

原文地址:http://python-history.blogspot.com/2009/02/early-language-design-and-development.html

从ABC到Python

Python最早的、最重要的影响来源是ABC,一门由Lambert Meertens,Leo Geurts和其他CWI的人在1980年代早期设计的语言。ABC是用于教学的语言,是个人计算领域里BASIC语言的替代物。它被设计成先做编程任务的任务分析,再做许多包含严格用户测试的迭代。我在ABC小组中的任务主要是实现语言和它的集成编辑环境。

Python的缩进样式直接来自ABC,但这个想法不是最早不是从ABC开始的–它已经被Donald Knuth所提倡成为了著名的程序风格概念。(occam语言也用这种格式。)然而,ABC的作者发明了由冒号来分隔引导句子和缩进内容。在早期的用户测试没有冒号方式后,我们发现没有冒号的版本的缩进含义让初学者在开始的时候搞不清楚。冒号的添加显著的使语言清晰了:冒号引起了人们对下文的注意,并且使上下的段落处于正常的位置。

Python的主要的数据类型也继承自ABC,尽管其中的一些有了改变。ABC的列表(list)是真正的包或者多重集合,使用了一种修改了的B-树来保证它总是有序的。它的表格(table)是联合的数组,简单的按照key排序。我觉得所有的数据类型都不适合来表达,例如,从一个文件里读入几行被认为是一个常用案例。(在ABC里你要用一个table来储存这些行,而这些行是通过行号来作为key的,但这样依赖插入和删除就很复杂。)所以我把列表类型变成了一个有插入删除操作的灵活的数组,使用户可以完全的控制元素在列表里的顺序。sort方法给出偶尔需要的有序结果。

我同时也把有序的表格的实现换成了哈希表。我选择哈希表因为我相信这样比ABC的B-树实现更快、更简单。后来从理论上证明了对于各种操作在空间和时间消耗上B-树渐渐的更优化,但从实践上来说,由于B-树的复杂性,这难以被正确的实现。同样的道理,小型表格的效率也成了次级优化。

我保留了ABC的不可变的元组(tuple)类型–Python的元组打包和解包操作是直接取自ABC的。因为在内部元组是用数组表示的,我决定添加像数组一样的索引和切片。

给元组添加像数组一样的接口的结果之一是我必须想出一些方法来解决当元组长度为0或1时的情况。我从ABC那里获得的一条原则是每个数据类型在打印或转换成字符串的时候,应该被表示成合法的语言分析程序的输入的形式。所以,我需要对长度为0和长度为1的元组做记号。同时,我不想让单一元组和没有圆括号的表达式之间没有差别,因此我了一个丑陋但实用的方法:逗号把一个表达式变成长度为一的元组,“()”则代表零长度的元组。在Python的元组语法中,圆括号并不经常用到,除了这里:我觉得用“没有”来表示空元组太容易让真正的排版模糊了。

Python的字符串与ABC的字符串用非常相似的(不可变的)语义开头,但用了不同的符号和基于0的索引。因为我目前有三种可索引的类型:列表、元组、和字符串,我决定把它们泛化成一个通用概念:序列。这个泛化使一些核心操作变得非常可靠,如获得长度(len(s))、索引(s[i])、分片(s[i:j])、和迭代(for i in s)都运作在任何序列类型上。

数字是与ABC不同的地方之一。在运行期,ABC有两种数字类型:exact型表示任意精度的有理数,approximate型表示有扩展指数范围的二进制浮点数。我没有选择有理数类型。(轶事:一次我尝试着用ABC来计算我的税务。程序看上去非常直白,但用了太长的时间去计算少量简单的数字。经过调查,我发现它用上千位的精确度来运算数字,但他们最终在输出的时候被四舍五入到盾(荷兰货币单位)和分。)因此我为Python选择了更传统的机器整数和机器二进制浮点数模型。在Python的实现中,这些数字分别被简单的表示成C语言中的long类型和double类型。

感觉到无限精确的数字有它的重要性,我加入了大数(bignum)类型,并把它称作long。我在几年前改进ABC的实现的时候已经实现了大数(在ABC的原始实现中,我对ABC的最初的贡献之一是使用了内部表示的十进制数)。因此,我在Python中用了这段代码。

尽管我在Python中加入了大数,我还是要强调我不想把大数运用在所有的整数运算上。通过我和在CWI的同事们写的优化Python的程序中,我知道整数操作表示了在多数程序中占了绝大多数。到目前为止,整数最常见的用途是在内存索引序列。因此,我猜想机器整数被用在绝大多数的情况下;而大数仅仅被用在“严密数学”或者计算以分来计的国家债务上面。

数字的问题

数字的实现,尤其是整数,是我犯了许多严重设计错误的一个方面。但我也在思考Python设计的时候学到了很多。

由于Python有两种不同的整数类型,我需要想出一种方法来在程序中分辨它们。我的方案是让用户在需要long型数的时候明确的在数字的末尾加上L(如1234L)。这是Python违反ABC的用户不需要关心底层细节实现的一个方面。

不幸的是,这只是许多大程序的一小部分细节。一个更过分的错误是我对于整型(integer)和长整型(long)的实现在某些例子上有略微不同的语义!因为int类型是用机器整数表示的,运算溢出时会默默的翻转32位数,就像C的long类型那样。另外,int类型一般是有符号数,但在按位运算和移位运算时是按照无符号数来算的,并会被转化成八进制和十六进制表示。另一方面,长整型数永远被认为是有符号数。因此,在参数分别是int和long类型时,一些运算会产生不同的结果。例如,一个32位运算1<<31(1往左移31位)会产生最大的32位负整数,1<<32会产生0,但1L<<31(长整型1往左移31位)的结果是长整型数2的31次方,1L<<32的结果是2的32次方。

为了解决这个问题,我作了简单的修正。我让多数运算操作在结果无法存下时抛出OverflowError异常。(唯一的例外是上面提到的“位运算”操作,我假设用户希望的是C语言里这些操作的行为。)在没有添加这个检查时,Python用户无疑已经开始写依赖符号二进制模运算2**32的语义(像C语言那样),但修改这个问题增加了社区用户转换时的困难。

尽管添加溢出检查看上去只是一个微小的细节变化,但痛苦的调试经验让我认识到这是个有用的功能。作为我早期的Python编程实验之一,我试过实现一个简单的数学算法来计算“Meertens数”,一个由Richard Bird为了CWI里ABC作者的第25年庆发明的消遣数学算法。前几个Meertens数很小,但当我把算法翻译成代码时,我意识到计算的中间结果比32位大的多。在我发现这一点前,它耗费了我又长又痛苦的时间来调试。于是我那时决定解决所有整数操作溢出的问题,并当结果不能用C语言的long类型表示的时候抛出异常。溢出测试的额外消耗比我实现为新结果选择分配对象时花费的总开销要小。

不幸的是,我难过的说抛出溢出异常也不是正确的解决方案。那时候,我正在沉迷在C语言的规则“对数字类型T的操作返回T类型的结果”。这条规则也是我在整数语义中的犯的另一点大的错误:切断整数除法的结果,我会在后面的blog文章中讨论这一点。事后来看,我应该让会溢出的整数操作把它们的结果提升成为long类型。这是今天Python工作的方式,但用了很长时间来做出这个转换。

除了数字问题,我从这次经验中获得了一个非常正面的事情。我决定Python中不应该有没有定义结果的值,反之,在无法运算正确的返回值时,总应该抛出异常。因此,Python程序不会因为未定义的值无声的在底层传递而出错。这对语言本身和标准库来说,仍然是相当重要的一点。

翻译Python历史:微软于1996年发布Python代码

This post a a Chinese translation of Greg Stein’s article “Microsoft Ships Python Code… in 1996” on a blog named “The History of Python”, which is started by Guido van Rossum.

原文地址:http://python-history.blogspot.com/2009/01/microsoft-ships-python-code-in-1996.html

非常感谢Guido让我分享我自己关于Python的历史!

我把我对Python的介绍放在另一篇文章里,结尾介绍了我们几个人在1991年的开始。那时我们在制作一个大型的处理B2C电子商务的客户端/服务器系统。客户TCP协议运行在旧的X.25网络上,是非常旧时代的东西了。

在1995年,我们认识到,与我们过去所相信的相冲突的,越来越多的客户实际上是联网的,我们需要给我们的客户(计算机销售商)提供一个系统可以访问连接到互联网上的客户。

我们的第一个问题就是要转换到一个完全基于浏览器的环境。我们的客户端不再使用了,所以我们要给客户们提供一个新的购物体验,而且服务器的基础结构要提供支持。那时,控制一个网络浏览器意味着为Apache和Netscape的HTTP服务器编写CGI脚本。通过CGI,我连接到我们已有的服务器后端来处理订单、维护购物篮、以及抓取商品信息。这些CGI脚本生成纯的、vanilla HTML(1995年还没有AJAX!)。

这项计划非常不理想,因为每一个请求花费很长时间来生成一个新的CGI进程。反应能力非常弱。因此,在1995年十二月,当我参加在华盛顿特区举办的Python研讨会时,我(从Digital Creations,最了解Zope的人)那里得知了一些Apache和Netscape模块在服务器进程运行的比较稳定。这些模块使用一个名为ILU的RPC系统来与后端的一直运行的进程交互。把这个系统替换进去后,CGI派生的高额开销就解决了,而且购物体验相当舒适!我们开始把原型转换成实际的代码。随着我们的投入,我们的系统看上去越完善,而且有更多的人加入这个项目。以后几个月的开发变得非常迅速(感谢Python!)。

在1996年一月,微软敲了我们的门。他们内部的电子商务系统的开发不断失败,他们需要一些懂得行业(那时我们做电子商务已经好几年了)而且聪明的人。当谈判开始时,我们在整个春天继续开发软件,在1996年六月完成了工作。

当我们带着我们的短小的Python代码到了微软,我们要完成如何把产品发布到Windows NT上。我们加入的小组里有很多Windows经验,我们制作了一个IIS插件通过管道来与嵌入我们的Python服务代码的后端NT服务器进行交互。经过从七月开始的疯狂冲刺,我们在1996年十月发布了微软商业服务器1.0版本(Microsoft Merchant Server 1.0)。

是的,如果你把外面的封装解开,隐藏在系统下面的,是一个Python解释器、一些扩展DLL文件、以及一堆.pyc文件。微软当然没有宣传这一点,但如果你知道从哪里寻找的话,它们确实在那里。

翻译Python历史:个人历史 – 第二部分,CNRI和之后

This post a a Chinese translation of Guido van Rossums’s article “Personal History – part 2, CNRI and beyond” on his blog named “The History of Python”.

原文地址:http://python-history.blogspot.com/2009/01/personal-history-part-2-cnri-and-beyond.html

Python研讨会(参看之前的文章)的结果是一份在CNRI(the Corporation for National Research Initiatives,国家研究研发公司)的工作。CNRI是位于维珍尼亚州来斯顿的一个非盈利的研究实验室。我在1995年四月份加入。CNRI的主管Bob Kahn是第一位向我指出Python与Lisp之间共同点的人,尽管两者从外表(语法)上完全不同。在CNRI,DARPA授权的移动媒介研究间接的给Python工作提供经济支持。尽管有DARPA支持的项目在使用Python,但没有太多对编程语言本身的直接支持。

在CNRI,我领导并帮助雇佣了一个小的开发小组来用纯的Python语言开发一个移动媒介系统。最初的小组成员是Roger Masse和Barry Warsaw,他们在NIST的Python研讨会上指出Python的bug。另外,我们还雇佣了Python社区的成员Ken Manheimer和Fred Drake。MIT的毕业生Jeremy Hylton原本是被雇佣来做文本检索工作的,也加入了团队。最初团队由Ted Strollo和Al Vezza管理。

这个团队帮助我创建和管理了另外的Python社区的基础,比如python.org站点,CVS服务器和不同的Python特殊兴趣小组的邮件列表。Python的1.3到1.6版本都出自CNRI。在很多年里Python 1.5.2版本是最流行和最稳定的版本。

GNU mailman也在这里诞生:我们最早用一个叫Majordomo的Perl工具,但Ken Manheimer发现它不容易管理,于是就找一个Python方案。他找到John Viega写的一些东西并接手管理。当Ken离开CNRI去了Digital Creations,Barry Warsaw接手了它,并说服了自由软件基金会(Free Software Foundation)采用它作为官方的邮件列表工具。因此Barry把它按照GPL(GNU Public Licence)许可发行。

Python研讨会仍然继续着。开始是一年两次,但由于工作量呈指数性的增长,它编程了年会。最初这些研讨会是自愿组织的,就像NIST(第一次),USGS(第二次和第三次),以及LLNL(第四次,并且开始了年度系列)。最终CNRI接手了组织任务,后来(和WWW及IETF会议一起)这些成为了Fortec商业行为的副产品。很快的参与人数达到了数百人。当我离开CNRI后一段时间后Fortec逐渐消失,全球Python会议成为了O’Reilly开源会议(OSCON)的一部分,但同时Python软件基金会(Python Software Foundation,见下)开始了一个名为PyCon的新的草根研讨会。

我们也在CNRI建立了第一个Python周边协会。为了回应Mike McLay和Paul Everitt创建一个后来结束在法规起草流沙中的“Python基金会”的努力,Bob Kahn出钱成立了“Python软件行动”(Python Software Activity),它是一个合法的独立实体,只是一个简单的工作在CNRI(非盈利)法律保护伞下的小组。PSA成功的聚集起大量的Python用户,但它缺乏独立性限制了它的效率。

CNRI也用DARPA的钱来资助JPython(以后会简单介绍Jpython)。JPython是一个在Java上的Python实现。Jim Hugunin最初在做MIT毕业设计时创立了JPython。他后来说服CNRI雇佣他来完成这项工作(或者是CNRI说服Jim加盟──事情发生在我度假的时候)。当Jim离开CNRI后不到两年加入Xerox PARC时,Barry Warsaw继续了JPython的开发。(很久以后,Jim也是IronPython的作者。IronPython是微软.NET平台上的Python。Jim也写了Numeric Python的第一个版本)。

CNRI的其它项目也开始使用Python。许多新的Python核心开发者都来自于此。特别是在MEMS Exchange项目工作的Andrew Kuchling、Neil Schemenauer和Greg Ward。(Andrew甚至在来CNRI之前就为Python做贡献了;他的第一个主要的项目是Python加密工具箱,一个第三方的给Python用户提供许多基础加密算法的库)。

在Python成功的过程中,CNRI尝试着提出一个更直接的而不是通过DARPA研究授权的资助Python开发的方式。我们建立了Python集团,就像X集团那样,最小加盟费是20000美元。然而,除了一个在惠普的小组,我们没有获得更多的牵引力,最终由于缺乏活力,集团倒闭了。另一项寻找资金的尝试接受DARPA资助的是全民编程(Computer Programming for Everybody,CP4E)。然而,它的资金不足以支持整个团队,而且它是一个让钱实际流动数年的完全的老男孩网络。那里没有我感兴趣的,我于是开始寻找新的机会。

最终在2000年dot com的极速发展还没有破灭的时候,我和CNRI Python团队的另外的三名成员(Barry Warsaw、Jeremy Hylton和Fred Drake)被说服加入了BeOpen.com,一个加利福尼亚刚起步的招聘开源开发者的公司。一个Python社区主要成员Tim Peters,也加入了。

如预期的那样,在跳槽到BeOpen.com后,出现了关于未来Python所有权的难题。CNRI坚持修更改许可协议并请求我们按照新的许可协议发布Python 1.6版本。我还在CWI时使用的旧许可协议有一个MIT许可协议版本。CNRI创立的许可协议对那份许可协议作了轻微的修改,主要是加上一句话说明CNRI放弃多数责任。在CNRI的律师修改后的1.6许可协议变的又长又罗唆。

我们和自由软件基金会的Richard Stallman及Eben Moglen有了几次关于这份新许可协议的一些部分的讨论。他们担心它将不与GPL兼容,因而威胁到GNU mailman的发展,因为mailman现在已经成了FSF的重要工具。在Eric Raymond的帮助下,CNRI Python许可协议被修改到FSF和CNRI双方都满意的程度,但最后的语句不容易被理解。关于它我唯一可以说出的好的方面是(再次感谢Eric Raymond的帮助)它是开放源代码首创的完全开源的许可协议。为反应两个后继产品的所有权变更,只对许可协议的文本做出了轻微的更改,先是BeOpen.com,然后是Python软件基金会,但事实上CNRI律师的手工工作仍然成立。

就像那时候的许多开始的公司一样,BeOpen.com的商业计划华丽的失败了。它留下了一大笔债,一些人严肃的怀疑一些公司长官的参与角色,和我的团队外的一些非常失望的开发者。

我的团队的幸运年,现在的PythonLabs,相当受欢迎。我们被数字创新公司(Digital Creations),最早的使用Python的公司之一,雇佣成为一个单元(Ken Manheimer在几年之前就去了那里)。数字创新很快把它们的名字改成他们的主要开源产品,Zope网络内容管理系统的名字,成了Zope Corporation。Zope的创始人Paul Everitt和Rob Page,以及他们的CTO,Jim Fulton,参加过NIST在1994年举办的早期的Python研讨会。

历史可以容易的走向非常不同的方向:除了数字创新公司,我们也考虑过VA Linux和ActiveState的工作。当时VA Linux在股票市场上是一颗升起的新星(曾经让Eric Raymond名义上成为了数百万富翁),然后戏剧性的倒闭了。回看过去我想如果ActiveState不位于加拿大的话,它不会是一个不好的选择,除了它的创始人Dick Hardt的饱受争议的个性。

我们在2001年创立了Python软件基金会,它是一个非盈利性的组织。它的初期成员是当时Python的主要贡献者。Eric Raymond是创立成员之一。我以后会再写这一段历史。

翻译Python历史:个人历史 – 第一部分,CWI

This post a a Chinese translation of Guido van Rossums‘s article “Personal History – part 1, CWI” on his blog named “The History of Python”.

原文地址:http://python-history.blogspot.com/2009/01/personal-history-part-1-cwi.html

Python的早期开发始于位于阿姆斯特丹的一个名为CWI的研究机构。CWI是Centre for Mathematics and Computer Science的荷兰语拼写的首字母。CWI是个有趣的地方,它接受荷兰政府的教育部门和其它研究拨款,做学术等级的计算机科学和数学研究。任何时间那里都有很多博士生,老辈的人或许还能记得它的原始名称:数学中心。在这个名字下,最有名的发明或许就是Algol 68了。

1982年晚期我大学毕业后开始在CWI工作,在Lambert MeertensSteven Pemberton领导的ABC小组当程序员。四、五年后ABC项目被终止,因为它缺乏显著的成就。然后我又到了Sape Mullender领导的CWI的Amoeba小组。Amoeba是一个基于微内核分布式系统,由CWI和阿姆斯特丹VU大学联合开发,由Andrew Tanenbaum领导。1991年Sape离开CWI去Twente大学当教授,我结束了CWI的由Dick Bulterman领导的一个新生多媒体小组的工作。

Python是我在CWI的一个直接产品。正如我将会在后面介绍的那样,ABC给了我Python的关键灵感、Amoeba给了我马上的动力、多媒体组让它成长。然而,就我所知,没有任何一笔CWI的基金是正式赞助Python的。事实上,Python仅仅是Amoeba和多媒体小组的一个重要工具。

我最初想创建Python的动机是Amoeba项目需要一个高级语言。我意识到用C语言来开发系统管理工具太费时间了。而且,在Bourne shell下做这个不能保证在其它的shell下也能正常工作。最重要的是作为一个完全新设计的分布式微内核系统,Amoeba的原子操作和其它能运行Bourne shell的传统操作系统相比是非常不同(而且更出色)的。所以我们需要一个语言来作为“C语言和shell之间的桥梁”。很长一段时间里,这就是Python的主要任务。

在这一点上,你或许会问“为什么不移植到已经存在的语言上?”我的观点是,那个时候没有许多合适的语言。我比较熟悉Perl 3,但它与UNIX的联系比与Bourne shell还要紧密。我也不喜欢Perl的语法──我对编程语言的口味受Algol 60样式的语言比如Pascal、Algol 68(都是我早期学的语言)和ABC这个我花费了生命中四年时间的语言影响很大。所以我决定设计一门我自己的新语言,借鉴所有ABC中我喜欢的东西并且修正我意识到的所有问题。

我第一个决定修正的是名字!就像事实那样,ABC小组没有给他们的语言取好名字。他们最初的名字是B,后来被放弃,因为会和另一个也叫B的语言混淆,而且那个B更古老,也更有名的。无论如何,B代表只是一个意义上的工作标题(这是一个玩笑,B是包含语言名字的变量名称,因此用斜体)。小组曾经举办过一个公开竞赛来征一个新名字,但没有一个是满意的。最后选用了内部的备用方案。这个名字想传达一个让语言和字母表一样简单的想法,但它从来没有让我感到信服。

所以,没有在上面分析名字问题,我决定在下面分析它。我选择了第一个想到的名字,从Monty Python’s Flying Circus来的,那是我最喜欢的喜剧演出之一。这点引用让我感觉非常适合一个“实验项目”。“Python”一词也是一个好记的不错的名字,而且也适合用名人命名语言的传统,就像Pascal、Ada、Eiffel那样。Monty Python团队或许在科技人群中不那么著名,但他们是极客们的最爱。它也同样适合CWI的传统──Amoeba小组用电视节目的名字来命名语言。

很多年我都抵抗住要把语言和蛇联系起来的诱惑。当O’Reilly想在他们的第一本关于Python的书《Programming Python》的封面上放上一条蛇的时候,我最终放弃了。用动物图像做书籍封面是O’Reilly的传统,如果要在Python的书的封面上印上动物,蛇是最合适的了。

决定了名称后,我于1989年十二月末开始了Python的工作,在1990年的头几个月有了一个可以运行的版本。我没有记笔记,但我清楚的记得我为Python写的第一份代码是一个我称作“pgen”的简单的LL(1)语法分析生成器。这个语法分析生成器仍然是Python代码的一部分,而且或许是所有代码中需要修改的最后一部分。Python的早期版本被CWI的一群人使用,但在1990年时还仅限于Amoeba小组内部。除我之外的核心开发者是我的同事Sjoerd Mullerder(Sape的弟弟)和Jack Jansen(在我离开CWI多年后他仍然领导Macintosh移植的开发)。

在1991年二月20日,我第一次通过alt.sources新闻组向世界发布了Python(我用uuencode分成21个包发布然后用户要用uudecode来合并成一个压缩的tar文件)。这个版本被标记为0.9.0,几乎是原字照抄了当时MIT给X11项目用的许可证,署名“Stichting Mathematisch Centrum”(CWI的上级组织)作为法律实体。所以,就像我写的其它东西一样,Python在Eric RaymondBruce Perens在1997年末推广“开源”一词之前就开源了。

当时立刻就有了很多回复。在这些回复的鼓励下,我在后几年定期的发布新版本。我开始使用CVS来跟踪更新和更容易的管理Sjoerd和Jack贡献的的代码(CVS最初是Dick Grune开发成一组shell脚本,他是ABC小组的早期成员)。我写了FAQ,定期发布到某个新闻组,来回答在web上常见的问题,并建立了邮件列表。1993年三月comp.lang.python在我的鼓励下建立了,但不是我亲自参与的。新闻组和邮件列表通过现在还在的一个双向网关联系在一起,尽管现在是mailman的一个功能了──mailman是一个优秀的开源邮件列表管理器,它本身也是用Python写的。

在1994年夏天,新闻组上的一篇名为“如果Guido被车撞了”的文章引起了关于成长中的Python社区对我本人贡献的依赖的讨论。讨论以Michael McLay邀请我到NIST做两个月的客座研究院而告终。NIST是the US National Institute for Standards and Technology(美国国家标准及技术研究所)的缩写,它的前身是National Bureau of Standards(国家标准局),位于马里兰州的Gaithersburg。Michael在NIST有许多“客户”对在标准相关的项目中使用Python感兴趣。我在那里帮助他们提高Python技术,并为他们的需要对Python做可能的改进。

第一次Python研讨会就是我在1994年十一月在那里召开的,NIST程序员Ken Manheimer提供了重要的协助和鼓励。当时有大约20名听众,其中半数仍然活跃在Python社团中,而其中的几人已经成为了开源项目的主要领导人(Jim Fulton领导了ZopeBarry Warsaw领导了GNU mailman)。在NIST的支持下,我也在Tom Christiansen组织的大约400人参加的Usenix Little Languages会议上做了主题演讲。Tom Christiansen是一位开明的Perl拥护者,他把我介绍给Perl的创始人Larry Wall和Tcl/Tk的作者John Ousterhout

下一篇内容:我是如何在美国找到工作的……

翻译Python历史:Python的简要时间表

This post is a Chinese translation of Guido van Rossum‘s article “A Brief Timeline of Python”.

原文地址:http://python-history.blogspot.com/2009/01/brief-timeline-of-python.html

Python的开发和流行是和许多其它的动态(和开源)编程语言如Tcl、Perl和后来的Ruby的同时代的。为了给Python一个更好的历史看法,下面这张表展示了Python的发布历史。在早期我没有严格的记录每件事,因此那时的日期并不精确。

发布日期 版本
December, 1989 开始实现
1990 CWI里内部发行
February 20, 1991 0.9.0 (发布到alt.sources)
February, 1991 0.9.1
Autumn, 1991 0.9.2
December 24, 1991 0.9.4
January 2, 1992 0.9.5 (只在Macintosh上)
April 6, 1992 0.9.6
Unknown, 1992 0.9.7beta
January 9, 1993 0.9.8
July 29, 1993 0.9.9
January 26, 1994 1.0.0
February 15, 1994 1.0.2
May 4, 1994 1.0.3
July 14, 1994 1.0.4
October 11, 1994 1.1
November 10, 1994 1.1.1
April 13, 1995 1.2
October 13, 1995 1.3
October 25, 1996 1.4
January 3, 1998 1.5
October 31, 1998 1.5.1
April 13, 1999 1.5.2
September 5, 2000 1.6
October 16, 2000 2.0
April 17, 2001 2.1
December 21, 2001 2.2
July 29, 2003 2.3
November 30, 2004 2.4
September 16, 2006 2.5
October 1, 2008 2.6
December 3, 2008 3.0

我给此时还在python.org网站上宣传的版本加上了链接。注意许多版本还有多个副版本,比如2.0.1。我没有把它们加上,否则这个表格就太长了。非常旧的版本的源代码包仍然可以从这里得到:http://www.python.org/ftp/python/src/。许多古老的二进制版本和其它的历史“文物”可以从上一个目录找到。

翻译Python历史:介绍与概述

This post is for translating an article named “Python’s Design Philosophy” by Guido van Rossum.

原文地址:http://python-history.blogspot.com/2009/01/introduction-and-overview.html

介绍

Python是目前最流行的几种动态编程语言(包括Perl、Tcl、PHP,以及新成员Ruby)之一。尽管它经常被认为是一门“脚本式”语言,但它确实是一门通用的编程语言,就像Lisp和Smalltalk以及其它语言一样。在今天,Python被用于从用一次就扔到的脚本到提供24×7小时不间断服务的大型服务器的各个领域中。它被用于GUI和数据库编程、客户端和服务器端的网络编程,以及程序测试。它既被科学家用来给世界上最快的超级电脑写程序,也被儿童用来学习编程。

在这个blog里,我将把焦点放在Python的历史上。特别是关于Python语言如何被开发、设计上的主要影响,犯的错误、学到的教训、以及未来的方向。

鸣谢:我欠了Dave Beazley很多这个blog的好的句子。(关于这个blog的更多的起源,请看我的另一个blog。)

鸟瞰Python

当人们第一次看Python时,他们常常对于代码的样子感到冲击,至少从表面上来看,很像常规的程序设计语言,比方C或Pascal。这并不是意外──Python从C上借鉴了很多语法。例如,许多Python的关键字(if、else、while、for等等)和C一模一样;Python的标识符和C有着同样的命名规则;大多数的基础操作符和C有着相同的含义。当然,很明显Python并不是C,一个主要的不同就是Python不是用括号而是用缩进来分组语句。例如,不是像C一样这样写语句

if (a &lt; b) {
max = b;
} else {
max = a;
}

Python完全抛弃了括号(同样抛弃了句尾的分号)并且使用如下的结构

if a &lt; b:
    max = b
else:
    max = a

其它Python和C样式的语言的不同是它使用动态类型绑定。在C中,变量永远必须被显式的定义像成某些特定的类型,比如说int或double。这个信息被用在进行程序的静态的编译期检查和分配用来存储变量值的内存地址。在Python中,变量只是简单的只想对象的名字。变量不需要在赋值前被定义,而且它们甚至可以在程序运行中间改变类型。像其它动态语言一样,所有的类型检查都是解释器在运行的时候进行的,而不是在每次的编译的时候。

Python的基本内建数据类新有布尔、数值(机器整数、任意精度的整数、以及实数和复数类型的浮点数),和字符串(8比特和Unicode)。这些都是不可变的类型,意思是他们是用创建后就不能改动的对象描述的。内建的复合数据类型包括元组(不可变的数组)、序列(可以改变体积的数组)和字典(哈希表)。

Python通过支持包(一组模块和/或包)、模块、类、方法和函数来组织程序。它提供if/else、while和可以循环所有“可迭代的”对象高级for语句来控制程序流程。错误处理方面,Python使用了(不可恢复的)异常。一条语句抛出了一个异常,try/except/finally语句来指定如何处理这个异常。当错误发生时,内建的操作就会抛出异常。

在Python中,所有可以被命名的对象都被称为“first class”。这意味着函数、类、方法、模块和所有其它的有名字的对象都可以在运行的时候被任意的传来传去、检查、并放在不同的数据结构(例如序列或字典)里。而且谈到对象,Python也有对面向对象编程,包括用户定义的类、继承、和运行期方法绑定的全面支持。

Python有多方面的标准库,是它能够流行的主要原因。标准库有超过100个模块而且还在继续增长中。这些模块包括正则表达式配对、标准数学函数、线程、操作系统接口、网络编程、标准互联网协议(HTTP、FTP、SMTP等等)、电子邮件处理、XML处理、HTML解析和GUI工具箱(Tcl/Tk)。

此外,还有数量相当庞大的第三方提供的模块和包,其中多数是开源的。其中有网络框架(要列出来就太多了)、更多的GUI工具箱、高效率数值库(包括对许多流行的Fortran包的封装)、关系型数据库接口(Oracle、MySQL和一些其它的)、SWIG(可以让任意C++库编程Python可使用的模块的工具)和更多。

Python(和其它动态编程语言)的一个主要的吸引力是看上去复杂的任务通常可以用非常短的代码表达。举例来说,这是一段简单的Python脚本,它抓取一个网页、扫描它并获取URL地址,然后输出其中的前10个:

# Scan the web looking for references

import re
import urllib

regex = re.compile(r’href=”([^”]+)”’)

def matcher(url, max=10):
“Print the first several URL references in a given url.”
data = urllib.urlopen(url).read()
hits = regex.findall(data)
for hit in hits(:max):
print urllib.basejoin(url, hit)

matcher(“http://python.org”)

这个程序可以容易的修改成网络抓取器,而且Scott Hassan确实曾经告诉我他用Python写了Google的第一个网页抓取器。今天,Google使用了上百万行的Python代码来管理它的各方面操作,从自动化建立到广告管理(免责声明:我目前是Google的员工。)

在底层,Python是结合字节码编译器和解释器实现的。在模块导入时,他们被隐含的编译,而且许多语言的语句在运行时需要编译器。尽管Python的事实上的标准实现是用C写的,并且可以运行在每一个的可以想象到的硬件/软件平台上,一些其它的实现也开始流行。Jython是一个运行在JVM上的版本并且和Java无缝集成。IronPython是.NET平台的版本,它和其它运星在.NET平台上的语言一样的被集成。PyPy用Python写的优化了的Python编译器/解释器(它仍然是一个EU基金下管理的研究项目)。还有一个Stackless Python,一个C实现的减少函数/方法调用对C语言的栈依赖的变种,允许并行、连续以及微线程。

翻译Python历史:Python的设计哲学

从LinuxToy上看到了Python的作者开blog写史的消息,马上进去看看,发现现在一共有两篇文章。因此想到现在做一个粗略的翻译可能会对中文读者有帮助,就抽了点时间翻译了其中的第二篇文章。我翻译的很不正规、也很不严谨。但对于不想做Python历史学家的普通读者应该能看通大略意思。

This post is for translating an article named “Python’s Design Philosophy” by Guido van Rossum.

原文地址:http://python-history.blogspot.com/2009/01/pythons-design-philosophy.html

后面的blog文章会讨论Python历史的(血淋淋的)细节。然而在那之前,我想详细的说一下在我设计和实现Python时帮助我做出决定的哲学上的指导方针。

首先,Python最初是被构思成一个个人的“实验”项目──没有官方预算,我希望能很快得到结果,以便说服我的老板支持这个项目(我做的相当成功)。这样产生了一些节省时间的规则:

  • 从任何可以的地方借鉴思想。
  • “任务应当尽可能简单的完成。”(爱因斯坦)
  • 做好一件事(“UNIX哲学”)。
  • 别过于担心效率──在最后需要的时候再优化。
  • 不要随大流。
  • 不要试图做到最好因为“足够好”就足够了。
  • (因此)抄近路是可行的,特别是当你可以在将来再完善。

其它的原则不是为了节省时间。有时它们反而是恰恰相反的。

  • Python的实现不应当限制在一个平台上。部分功能可以不跨平台,但核心一定要可以随处工作。
  • 不要用机器可以处理的细节去打扰用户(我不总是遵守这点,后面的章节会讲一些惨痛的后果)。
  • 支持、鼓励平台无关的用户代码,但不要切断访问平台特性的功能(这点与Java完全不同)。
  • 一个大型的复杂的系统应当有不同层次的扩展性。这点最大化了用户的机会,或多或少的帮助了他们。
  • 错误不应当是致命的。这样,在虚拟机还正常工作的时候,用户的代码可以从错误中恢复。
  • 同时,错误应该给出提示。(这两点让我决定在实现中使用异常)
  • 用户代码中的bug不应当导致Python解释器的异常行为。也就是说,解释器的崩溃与用户无关。

最终,我对好的编程语言的实现有了一些想法。多数是我在我的第一次语言实现与设计经验──ABC小组中获得的。这些想法很难用语言表达,因为他们多数是我对一些像优雅、简单、可读性之类概念的主管思考。

尽管我会讨论更多的ABC给Python的影响,我想先单独提出一条可读性的规则:应当保守的使用标点符号,就像在书面英语和高中代数一样。个别在编程语言中长期使用的符号是例外,比如“x*y”表示乘法,“a[i]”表示数组元素,或者“x.foo”表示属性。但Python不使用“$”来表示变量,或用“!”来表示带有副作用的操作。

Tim Peters是一位Python的长期用户并在最终成为了多产坚定的开发者。他在《Python之禅》一文中总结了我的一些未公开的设计原则。我全部引用在这儿:

  • 漂亮比丑陋要好。
  • 直接比含蓄要好。
  • 简单比繁复要好。
  • 繁复比复杂要好。
  • 平铺比嵌套要好。
  • 稀疏比密集要好。
  • 可读性很重要。
  • 特例不能破坏规则。
  • 尽管实用优于纯正。
  • 错误永远不能安静的通过。
  • 除非明确的让它安静。
  • 拒绝在模糊的地方猜测。
  • 应当有一种,并且最好只有一种,明显的方法去做一件事。
  • 尽管开始时那种方法并不明显,除非你是荷兰人。
  • 现在要比永远不更好。
  • 尽管永远不常常比当前要好。
  • 如果一个实现很难解释,那么它就是一个不好的想法。
  • 如果一个实现容易解释,那么它可能是一个好的想法。
  • 名称空间是一个很伟大的想法,让我们做的更多。

尽管我在ABC的经验很大的影响了Python,ABC小组也有几条Python完全排斥的设计原则。许多时候,Python有意识的防止这样做:

  • ABC小组努力的做到完美。例如,他们使用被证明为对处理大型数据有很高效率的基于树的数据结构算法(但对小型数据却不那么好)。
  • ABC小组希望尽量完全的从“巨大、不好的计算机世界”中隔离用户。在那里,不仅数字没有限定的范围,字符串没有限定的长度,集合没有限定的体积(在可用内存之外),而且用户也不应该处理文件、磁盘、“存储”或其它程序。ABC应当是用户需要的唯一工具。这点也让ABC小组创建了一个仅仅用于ABC的完全集成的编辑环境(当然有从ABC环境中逃离的方法,但它们通常是些事后的观点,而不是直接通过语言本身来达到的)。
  • ABC小组假定用户没有之前的计算机使用经验(或者他们希望用户忘记那些经验)。因此他们引入了一些新的“对初学者友好的”术语,而不是使用标准的编程语言的术语。例如,子程序被称为“how-tos”,变量被称为“locations”。
  • ABC小组没有按照头脑进化的路线来设计ABC,也没有期待用户参与到语言的设计中来。ABC被设计成一个封闭的系统,以设计者的最大努力把它做到完美。用户不被鼓励去“看看盖子下面”。尽管在项目的后期有关于对高级用户开放部分实现的讨论,但永远没有实现。

从许多角度上来说,我在创建Python的时候用的设计思想大概是它获得巨大成功的主要原因。没有努力去做到完美,早期的使用者们发现Python工作的“足够好”的满足了他们的需求。通过用户的增多,对语言的改进建议被逐渐的吸收进来。就像我们将要在以后的章节中见到的那样,许多这些改进导致了重大的改进和语言核心部分的重构。哪怕是今天,Python也在继续演化中。