Python的起源

ABC语言或许过于超前于时代,而Python恰逢其时。无论如何,我相信在ABC语言开发过程中形成的理念——只要这些理念在Python中得到延续

 💬 72 条评论 |  python | 

1970年6月21日星期天,伦敦大波特兰街一栋办公楼里,一台电传打字机突然启动。在“幸福家庭”的标题下,机器哗啦哗啦打出连串英文句子,诸如“狗坐在婴儿身上”和“泰德叔叔陪妹妹玩耍”。生成这些输出的“幸福家庭”程序,是由一位毫无编程经验的参与者在周末编写的。她参加了计算机艺术协会组织的“非数字编程”课程工作坊。[1]

近五十年后的2019年10月26日,在伊斯坦布尔,一位年轻女子的眼睛因成功运行人生首个程序而闪闪发亮。她正参加由国际非营利组织“Django Girls”举办的编程工作坊,该组织通过免费一日编程课程赋能女性。[2]

元素周期表

1970年伦敦工作坊使用的编程语言是TELCOMP[3]——一种类似BASIC的简单非结构化语言,但并非现今的BASIC,而是当时的非结构化BASIC。[4]而2019年伊斯坦布尔工作坊教授的语言是Python[5]——由Guido van Rossum设计的编程语言自1991年低调发布后持续走红[6]。尽管这两场活动在时空维度上相距甚远,历史的弧线却将它们紧密相连。

时光回溯

要完整阐释这两件事的关联,必须追溯至1960年代末的计算机编程领域。当时的“剧中人物”是莱奥·格特(Leo Geurts)——身为程序员的他,与身为初级研究员的我,同在阿姆斯特丹数学中心(当时简称“MC”,后更名为数学与信息学中心CWI)任职。[7] MC给予我们相当大的自由度选择研究课题,这些课题通常致力于探索计算机能力的边界。我们长期致力于研究计算机在艺术与音乐领域的应用——并非将其当作昂贵的描图仪或音乐盒,而是作为忠实的仆人,依据我们设计的算法规则创作作品,这些规则我们希望能够体现有趣的创造性原则。我们于1968年计算机艺术协会创立之初便加入成为积极成员[8],并在伦敦等地的1970年研讨会担任讲师或导师。当时个人电脑尚未问世,绝大多数人甚至从未见过计算机。参与工作坊的艺术家、作曲家和建筑师们都不懂编程语言;短短两天内,我们必须同时传授编程语言和编程原理。

当时运行程序的常规方式是批处理。程序员将程序以打孔卡片包或打孔纸带卷的形式提交至计算中心柜台,只要程序没有致命错误,通常两小时内或次日就能取回输出结果。这种模式显然无法满足周末课程的需求。但TELCOMP属于当时所谓的“会话式语言”——用现代术语说就是交互式实现。电传打字机充当计算机终端,连接至由Time Sharing公司运营的分时系统主机。用户只需将程序以编号步骤序列输入后,发出DO命令即可运行程序并即时获取结果。

学习这门语言本身并不复杂。TELCOMP仅有十五条指令和两种数据类型:数字与数字数组。但将其用于将想法转化为代码却成了瓶颈。这些命令和类型均在极低层级实现,与它们所具象化的抽象概念相去甚远。因此无法提供合理组织材料的有效手段。即便是最简单的项目,也很快演变成所谓的“意大利面代码”[9]——一团无法梳理的混乱。

我们当然知道存在更优越的语言,例如ALGOL 60[10]。虽然完整的ALGOL 60语言或许比本项目所需更为复杂,但我们本可教授其简化子集。未采用ALGOL 60的原因在于,它并非为对话式使用而设计。

编程语言设计与简洁性

除了一些刻意设计成玩笑的编程语言(如INTERCAL[11])外,语言设计师通常不会刻意让语言变得难以学习或使用。易学性和易用性都是编程语言应具备的理想属性。然而我常感到,语言设计的这一方面并未始终获得应有的重视。对设计者而言看似简单的事物,对语言学习者未必同样轻松。

首先,编程语言本质是将算法思想转化为可由自动机执行的表达工具。功能工具的设计并非精确科学,而是要在潜在冲突的设计目标间寻求平衡。通用编程语言更像工具箱,其组成部件需如Meccano积木般灵活组合,实现多样化的协同运作。除最基础的语言外,设计者需做出数百项设计决策。从众多可能性中审慎抉择,既需要对设计空间的认知与探索意愿,也需要识别权衡关系并评估替代方案的能力。此时设计哲学便能为设计者提供指引,它可通过若干设计规则体现——这些规则虽不能是死板的条条框框,却必须反映设计者的目标。

工具的简洁性包含两个维度:功能易学性与功能易用性。程序员的任务是将想法转化为代码。若编程语言的元素能与程序员思维中的概念相匹配,且具有任务导向性,这一过程将显著简化。乍看之下,这两种简洁性似乎相互矛盾。事实上,极简语言虽易于学习,却可能增加编程难度。不仅需要更多代码行,随着程序规模扩大,编写正确代码的难度也会急剧上升。反之,若试图打造类似瑞士军刀的多功能工具,塞入所有可想象的功能,则会产生复杂难学的语言——但使用起来肯定很方便?未必如此。

程序员必须将原始任务分解为子任务,子任务再分解为子子任务,如此递进,直至达到可用编程语言工具集直接处理当前任务的层次。若语言功能过于丰富,实现路径将层出不穷,在众多选项中抉择反而会成为沉重的思维负担。以这种方式不断丰富语言功能会导致收益递减——直至最终任何微小收益都荡然无存。与其将各种潜在有用功能塞进工具集,更优方案是精选少量强大的任务导向型功能,并确保它们能协同高效运作。

ABC项目

在为艺术家们举办编程研讨会的数年间——主要在英国和荷兰——格茨和我对现有编程语言的缺陷日益感到沮丧。[12] “为何没有一种语言能兼具两种特质?”我们不禁思索,“既拥有ALGOL 60的强大功能与简约优雅,又具备BASIC和TELCOMP的精简规模与对话式易用性?”这份沮丧促使我们在1975年启动项目,致力于设计这样的语言。我曾近距离观察过ALGOL 68的设计过程[13]——该语言本是ALGOL 60雄心勃勃的继任者——也目睹了1970至1974年间的修订历程。两次修订中,诸多明显改进因“提议过晚”而未能采纳,这让我深知设计过程中预留多次迭代空间至关重要。我们还决定在最终满意前暂不确定新语言名称。为标识该语言,我们选取未初始化字符串变量名B作为占位符,直至设计完成。字母“B”既取自“初学者”(beginner)首字母,也因该项目旨在成为面向零基础者的教学语言。遵循数学变量命名惯例,我们采用斜体呈现该符号。最初的近似版本B0尚未经过深入考量,更多是为验证设计偏好而进行的实验。最终该语言在一年内完成并发布。[14]尽管与最终成果存在显著差异,但某些核心要素始终贯穿所有迭代版本。B0指令PUT 1, 2 IN A, B将值1赋给名为A的变量,值2赋给名为B的变量。指令PUT A, B IN B, A则交换这两个变量的内容。[15]在多数其他语言中,此类交换需借助第三个辅助变量分三步完成:(1) PUT A IN X; (2) PUT B IN A; (3) PUT X IN B。后期版本中,随着支持大小写混合输入输出的设备普及,语法演变为PUT a, b IN b, a,但赋值指令结构及多值关联赋值的特性得以保留。更引人注目的是缩进的使用。尽管在ALGOL 60及其衍生语言(如Pascal)的程序中,常将缩进作为排版布局特征来清晰呈现命令分组,但这完全是可选的呈现方式,纯粹是为了便于人类读者理解。在P. J. Plauger题为《编程语言中的信号与噪声》[16]的文章中,我们发现了当时颇具革命性的理念:“让编译器解读与人类相同的信号,以缩进控制分组”,这一建议我们欣然采纳。随后在B0程序中,缩进被强制用于标识命令组的关联性,这一设计选择在所有版本迭代中得以延续。[17]

我们并非怀揣明确的设计哲学而起步,而是让设计理念在实践中自然生长,最终凝结为核心设计原则。为服务目标用户——零基础初学者,我们致力于隐藏底层实现细节,转而提供强大的高阶任务导向功能。我们最重视的价值之一是统一性,既体现在语言构造呈现的规范性(“语法”),也体现在其含义的无歧义性(“语义”)。多数程序员并未真正掌握其常用语言的所有细节,更不能指望初学者快速精通新语言。某种程度上,学习新编程语言如同学习新自然语言:不规则现象与例外情况会成为通往精通之路的绊脚石。自然的学习方式是先从实例入手,再由此推导出普遍规则。例如幼儿可能说“狗咬了他”,错误地将规则动词的过去式规则套用在不规则动词上。尽管一致性对人工语言而言看似可取且可实现,但实践中却鲜有体现。多数语言(或其实现)都存在诸多限制与例外,这些限制既笨拙又看似随意,使语言更难学习和使用。随着新语言设计的推进,我们发现设计决策中存在规律。我们试图捕捉每种规律并将其编纂为设计规则,这种方法有助于提升一致性。其中部分规则已被他人发现,例如普劳格(Plauger)的文章中就曾提及。

语法统一性要求被编纂为统一性规则,普劳格将其概括为格言:“相似事物应以相似方式表达”。另一条更侧重语义的设计规则被称为合理预期原则。人类视觉感知存在一种称为良好延续性原则的特性,该特性体现了格式塔分组法则之一[18]。当物体仅部分可见时,人类视觉系统会根据可见部分的形状推断出被遮挡部分的形态。为使形状完整,视觉会根据上下文推断不可见部分。例如当不透明圆盘遮住矩形一角时,人们倾向于认为矩形边线在圆盘下方延续,从而感知完整矩形。当遮挡物移除后,观察者可能发现自己被欺骗了:实际被遮挡的物体并不完整。但这种意外效果常被魔术师用作戏法。我们希望避免学习者遭遇此类意外。公平预期原则规定:若用户基于相似构造的推演,合理预期某构造有效且具有特定含义,则该构造必须有效并具备该含义。设计越遵循此原则,用户就越有理由相信该规则在下次使用时仍将生效。实际上,这种方法对语言发展产生了自我强化的作用。另一项设计要求是工具经济性规则:不同工具应真正服务于不同功能。若发现不同功能在概念上存在重叠,则应将这些工具统一。该规则的应用促使语言整体功能填补更多空白,从而满足公平预期规则的要求。

1981年,历经两轮迭代后,我们以《草案提案》[19]形式发布设计方案。随后我迅速编写了本应是临时产品的实现版本,以便通过面向初学者的教学收集反馈。

次年,我接受纽约大学库朗研究所计算机科学系为期一年的客座副教授职位。罗伯特·杜瓦尔作为B项目的热忱支持者,曾指导学生完成多个B1实现项目。管理委员会邀请史蒂文·彭伯顿——原计划以客座研究科学家的身份任职一年——在此过渡期担任正式实现工作的开发负责人。在我赴纽约期间,阿姆斯特丹的实现团队迎来了新成员圭多·范罗瑟姆的加入。

SETL与高级数据类型

早先造访纽约大学时,我接触到由数学多面手杰克·施瓦茨设计的超高级语言SETL。[20]这位远见卓识的学者著有数本数学基础著作。在某些方面,SETL几乎与当时处于初始版本B1阶段的B语言形成鲜明对比。基于数学集合论概念,SETL的目标用户似乎是数学家。而设计B时,我们仅要求掌握最基础的算术与代数知识。但这两种语言在更深层次存在共通点:设计哲学都聚焦于为程序员提供少数但极其强大的工具。SETL彻底颠覆了当时笼罩在高级语言设计(包括ALGOL 68)上的思维定式。这些语言的设计者及其同行所处的时代,处理器指令的执行时间以毫秒计而非微秒计。1980年代初耗时一小时的计算,在1950年代初可能需要数周才能完成。数十年来,计算机时间被视为远比程序员时间珍贵,这种观念深刻影响了整整一代程序员及其设计的语言。因此编程语言的构造被设计成与计算机硬件指令集直接映射。当然这种映射并非完美——相较于直接用机器码精心编写的程序,执行速度必然存在损失。早在1960年代,针对耗费计算机时间的高级语言有害影响的抨击就屡见不鲜。SETL的设计理念基于这样的哲学:随着计算机日益高速,人类时间将比计算机时间更具价值,而SETL工具集的效率不应以计算速度衡量,而应以其概念力量为准绳。

在SETL语言中编写过若干算法后,我亲身体验了它的强大之处——这种力量完全源于其内置的高级数据类型。其中尤为强大的是集合和映射(亦称“关联数组”),它们存储的数据不仅可通过连续整数索引,还能通过任意值进行索引。程序员可以创建一个名为whosaid的简单名言数据库,其中值“笛卡尔”可存储于位置whosaid[“我思故我在]。这些高级类型使得用SETL仅需几步就能实现B1中需要多步的算法。而B1却明显违反了公平期望规则,仅允许整数作为数组索引。这一设计决策源于恐惧:我们曾担心目标定得太高,会使语言无法在当时初现市场的个人计算机上实现。但德瓦尔尤其说服了我:这意味着我们是在为过去设计,而非面向未来。这促使我们重新设计初学者语言的数据类型系统。这次我们仅以易学性和易用性为标准筛选候选系统。最终胜出的方案竟与SETL的数据类型系统惊人相似。可选的数据类型系统数量庞大,为使筛选过程可控,我编写了程序来选出具有竞争力的(帕累托最优)候选系统。有趣的是,这个筛选程序本身恰巧是用SETL编写的。最终胜出的类型系统成为B2的类型系统,并在1985年以“ABC”之名发布的最终版本中保持不变。用符号表示,我们执行了命令PUT “ABC” IN B。[21]此时距离B项目启动已过去十年。

终点与起点

1983年9月,我重返阿姆斯特丹,回到计算机中心(MC)。在我离职期间该机构更名为CWI(计算机科学与应用研究所)。计算机科学(荷兰语称informatica)自MC成立之初便在其研究中扮演重要角色,此次更名正是对此的明确体现。彭伯顿作为ABC的第三位首席设计师继续留在团队。在从B2到ABC的最终设计迭代中,我们重新审视了语言的几乎每个方面,以探寻任何可能的改进空间,无论多么微小。每周召开全体成员参与的团队会议,范罗斯姆经常提出修改建议。其中部分建议被采纳,多数未被采纳,但每项建议都经过了认真考量。在编程语言设计中,鲜有提案能仅具优势;几乎所有变更都伴随利弊权衡。权衡这些因素以作出裁决往往是微妙之事。许多提案会违反设计规则——这些规则虽是对整体设计理念的不完美规范,却仍是重要准则。

1984年项目获得IBM PC机,不到一年时间我们就让ABC在该机器上运行,并准备向全球发布。

一个简单示例足以展现TELCOMP与ABC的巨大差异。冒泡排序虽是广为人知的排序算法,但效率低下,尤其处理大规模数据集时。然而因其简单性,常被用于阐释基础算法概念,并作为编程语言的初步比较对象。以下代码示例展示了TELCOMP与ABC中实现的冒泡排序:

TELCOMP

1.01 DO PART 2 FOR I = 1:1:N-1
2.01 DO PART 3 FOR J = 1:1:N-1
3.01 DO PART 4 IF A[J] > A[J+1]
4.01 SET X = A[J]
4.02 SET A[J] = A[J+1]
4.03 SET A[J+1] = X

ABC

FOR i IN {1..#a-1}:
  FOR j IN {1..#a-1}:
    IF a[j] > a[j+1]:
      PUT a[j+1], a[j] IN a[j], a[j+1]

TELCOMP指令前的编号不可或缺,它作为标签用于指定计算的延续。ABC语言中则无需此类标记。TELCOMP程序由四个编号的“部分”构成,类似于以数字命名的子程序。每个部分包含一个或多个编号步骤。完成各部分步骤后,控制权将返回至调用该部分的步骤续行处——即DO PART指令。TELCOMP版本要求用户预先将变量N的值设为数组A的长度。输入这些指令后,用户仍需直接执行DO PART 1指令才能启动排序过程,而ABC指令可直接使用。

ABC并未取得我们期望的成功。项目启动之初,我们天真地认为,将计算机编程基础纳入高中标准课程只是时间问题,而ABC正是最理想的选择。部分学校的教师确实开设过使用ABC的实验性编程课程。然而当“信息学”最终在1980年代末被纳入荷兰高中课程时,这门课竟沦为文字处理软件(WordPerfect)和电子表格软件(Lotus 1-2-3)的使用教程——如今这两款产品都已成为历史尘埃。我们面临的重大障碍在于:如何让剩余的潜在用户群体——非职业计算机爱好者——知晓该语言的存在。当时我们熟知的互联网尚未诞生,其前身ARPANET仅限学术与军事用途。出于某种原因,CWI管理层拒绝在当时计算机爱好者权威期刊《Dr. Dobb’s Journal》刊登广告。我们唯一能做的,就是将软件拷贝在软盘上邮寄给少数知晓项目并主动联系的幸运者,总计数百人。研究所理事会违背我们的意愿,坚持在启动界面显示“版权所有 (c) 阿姆斯特丹数学中心基金会,1985”字样,以此主动阻止用户向朋友传播副本。顺带一提,同年理查德·斯托曼在《Dr. Dobb’s Journal》杂志发表了《GNU宣言》[22],该宣言后来成为自由软件运动的号召书。

1988年,范罗森姆被派往自由大学与CWI联合开展的“Amoeba”项目,该项目旨在开发分布式操作系统。1990年1月某日清晨,他邀我观摩其最新心血——名为“Python”的编程语言。这门语言诞生于圣诞至新年假期期间。我记得当时并未特别着迷,其创新意义对我而言尚不明晰。直到我注意到项目中的程序员们——尤其是范罗瑟姆之后全球首位Python程序员杰克·詹森[23]——都成了它的狂热用户,我才开始认真关注。

Python与成功的奥秘

设计师有时试图通过模仿他人产品来复制成功。虽然这种策略在时尚产品或电影领域可能短期奏效,但对编程语言而言毫无意义。成功的语言会催生大量基于该语言开发的软件,并培养出精通该语言的程序员队伍。若改用其他语言,组织机构的软件基础将面临重写,程序员也需重新培训。这一过程会产生切实的成本,除非新语言在某些关键方面具有压倒性优势,否则根本无利可图。它绝不能仅仅是简单的模仿。

将编程语言领域视为生态系统颇具启发性——每种语言占据独特生态位。FORTRAN专攻高性能科学计算领域,擅长处理高强度数值运算;COBOL则立足于数据记录文件管理,成为行政应用的基石。C语言专为系统编程设计,最初正是为Unix操作系统量身打造。正如世上不存在万能运输工具,真正通用的万用编程语言亦不存在;对于特定高度专业化的应用领域,总能设计出更契合该领域独特需求的定制化语言。

作为Amoeba项目的一部分,需要将独立开发的软件模块相互连接。当时,Unix等操作系统自带名为“shell”的程序,用于向操作系统发出直接指令。这些指令包括连接应用程序所需的功能,例如将一个程序的输出作为另一个程序的输入。一组称为“脚本”的shell命令序列可存储于文件中,该文件名即可作为新shell命令使用。这虽属于编程范畴,但当时的shell语言并非为编程而设计,用于此目的极为笨拙。更糟的是,当时无法直接与Amoeba进程交互,必须用C语言编写进程存根。虽然转向C语言看似更优解,却会迫使程序员陷入编辑-存储-编译-运行-调试的繁琐循环。显然亟需一种设计精良的“脚本语言”,以实现与外部进程的交互。Python最初正是为Amoeba项目设计的高级脚本语言。ABC语言完全不适合此用途——它自成体系,其设计初衷便是将用户与外部世界隔绝。Python则被明确设计为与外部世界对接。[24]当时高级脚本语言领域唯一的竞争者是Perl的早期版本,但其文档不完善且无法保证持续支持。此外,尽管Perl实现了预期功能,却混杂着从其他语言借鉴的特性,整合时几乎未考虑一致性。

尽管应用领域截然不同,范·罗森姆仍深受ABC项目的设计哲学与规则启发。Python的设计理念后来由早期布道者蒂姆·彼得斯以颇具诗意的笔触阐述,形成如今广为人知的《Python禅》。[25] 其中诸多箴言与ABC的设计理念遥相呼应:“错误绝不应悄然溜走”、“面对模糊性,拒绝猜测的诱惑”,恰与我们命名的“逻辑错误规则”相契合。同样地,“特殊情况不足以打破规则”体现了公平预期规则;而“实现方式应当只有一种——最好是唯一一种”则诠释了工具经济性规则的精髓。与ABC语言相似,Python用户可直接输入代码并即时运行;该语言拥有简洁明晰的语法、高级数据类型,且无需变量声明。如此便捷的工作流程使其早期用户——系统程序员们——开始将该语言应用于原定领域之外的众多任务。1991年初,一个经过适度增强的版本(附有详述Unix系统安装方法的文档)作为开源项目发布于Usenet,随即被全球程序员广泛采用。

适应需求变化的能力是任何编程语言长期存续的关键属性。1957年诞生的FORTRAN与1960年问世的COBOL至今仍活跃于编程领域,但都经历了显著演进。同样,现已发布至3.0版本的Python虽非1990年的模样,却始终保留着其核心优势:一致性、无冗余限制及工具精简性。强大的数据类型在Python中扮演着核心角色,正如其在ABC及更早的SETL语言中的地位。

以下代码示例展示了两种版本的冒泡排序算法,分别采用ABC和Python语言实现。

ABC

FOR i IN {1..#a-1}:
  FOR j IN {1..#a-1}:
    IF a[j] > a[j+1]:
      PUT a[j+1], a[j] IN a[j], a[j+1]

Python

for i in range(len(a)-1):
  for j in range(len(a)-1):
    if a[j] > a[j+1]:
      a[j], a[j+1] = a[j+1], a[j]

两种语言的语法相似性显而易见。另一项相似之处在于,它们都不要求在程序中声明使用的变量——这减轻了负担,却未以牺牲类型安全为代价。在几乎所有编程语言中,冒泡排序算法的代码仅适用于单一元素类型(如数字)。若需对文本字符串进行排序,则必须另写一段代码。在Python中,如同ABC语言,上述代码可适用于任何定义了比较运算符>的元素类型,例如字符串。尽管许多编程语言无法处理十位整数,但ABC和Python均未对整数大小设置上限。表达式 (10999 + 1) – 10999 的值精确等于 1,但逐步求值需要对两个数进行减法运算——若采用十进制表示,每个数都需使用一千位数字。在大多数语言中,程序会终止运行或输出0而非1。而Python和ABC均能正确输出结果。这不仅是实现特性,更是语言规范的硬性要求。

无论Python特性多么引人入胜[26],任何简要概述都无法全面展现其设计精髓——该语言无法通过孤立评估其组件来评判。衡量Python品质的更佳标尺,在于其对功能取舍的明智抉择。其真正实力体现在这些组件如何协同运作以满足程序员需求。

Python自三十年前作为无人问津的个人项目诞生以来,其普及度呈现惊人增长,但并非一蹴而就。相反,这是一段漫长、缓慢而稳健的上升历程。在程序员需求持续旺盛的时期,Python的易学性赋予其竞争优势。其简洁的语法与语义使得维护Python编写的软件基础比其他语言更轻松——考虑到软件维护成本远超开发成本,这点尤为重要。其日益普及还得益于庞大的应用程序库——这些由Python社区秉持开源精神开发的领域专用功能模块集合,可通过可搜索的Python软件包索引[27]轻松获取。无论是初创公司急需开发网站还是人工智能应用,Python库都能提供快速入门支持。涵盖天文学、密码学、数据科学、金融服务、基因组学、多媒体等众多领域的模块应有尽有。Python的设计使库与模块的使用变得简单,而这正是ABC设计所欠缺的。Python还使新库的创建变得轻松,从而鼓励用户将新开发的应用程序库贡献给公共仓库。

无论从何种标准衡量,Python如今都稳居全球三大最受欢迎编程语言之列——且常居榜首。[28] 无论Python本身具备何种内在优势,若不考量其低调创始人兼首席设计师Guido van Rossum所发挥的作用,便无法解释该语言的惊人成功。在Python社区的支持与共识下,范罗瑟姆对所有语言变更拥有最终审批权,因而被戏称为“终身仁慈独裁者”。[29] 贯穿Python演进历程,范罗瑟姆稳健的引领始终守护着其设计理念的完整性。

前传与后记

我第一次见到范罗森是在1980年代初,当时我们共同参与一个团队,为荷兰和平主义社会主义党设计开发会员管理系统。该党后来与其他几个小党合并,组建了绿党(GroenLinks)。该党成员数量在过去几年里翻了一番,此前一直手动处理所有行政工作的三名雇员不堪重负。幸运的是,小型计算机的价格正在迅速下降,因此该党决定购买一台。由于预算有限,该党无力聘请商业软件公司开发所需系统,于是组建了志愿者团队,采用COBOL语言自主开发。开发过程中遭遇严重瓶颈:随迷你计算机附带的编辑器操作极为不便,用户每次只能查看一行代码。由于计算机不支持多任务处理,编译(过程极其缓慢)和测试必须等到编辑会话结束才能进行。结果进展如同蜗牛爬行般缓慢。当时还是大学生的范·罗瑟姆出人意料地开发出新编辑器,不仅大幅提升易用性,还高效利用了大部分可用屏幕空间,令团队成员惊叹不已。他用COBOL语言编写了这个编辑器,而他正是通过这个项目才接触到这种语言。当时ABC项目正计划扩充开发团队,我注意到范罗瑟姆的编程天赋,便鼓励他申请这个职位。毕业后,他于1982年11月1日正式加入B团队开启职业生涯,并再次以出人意料的方式令团队惊叹——他开发出全新的ABC结构化编辑器,该编辑器能完全识别ABC的语法结构。

本文开篇提及的2019年伊斯坦布尔研讨会并非同类活动的唯一案例。实际上这是因新冠疫情暂停的系列工作坊中的第八期。在为期一天的活动中,参与者从简单的单行程序(如print(‘Hello, Django Girls!’))起步,到结束时已能编写自己的网站。这类Django Girls工作坊并非伊斯坦布尔独有,而是遍布全球。在这些工作坊中,Python不仅作为首选语言教授,更已成为编程入门课程的首选语言。Python如今占据了ABC语言最初设计的细分领域,事实上它已占据多个细分领域,成为真正的多领域通用语言。

任何事业的成功都难以归因于单一因素。[30]除上述因素外,运气同样发挥着作用。ABC或许过于超前于时代,而Python恰逢其时。无论如何,我相信在ABC开发过程中形成的理念——只要这些理念在Python中得到延续——至少产生了积极影响。


兰伯特·梅尔滕斯是加州帕洛阿尔托凯斯特雷尔研究所的研究员。尽管其主要研究工作在阿姆斯特丹CWI和凯斯特尔研究所完成,他曾任教于纽约大学、代尔夫特理工大学及乌得勒支大学,并担任国际信息处理联合会(IFIP)算法语言与演算工作组2.1主席。


  1. 计算机艺术学会周末课程”,《PAGE》(计算机艺术学会通讯),第9期(1970年)。 ↩︎
  2. Django Girls伊斯坦布尔第8期”,(土耳其语),Django Girls,2021年。 ↩︎
  3. TELCOMP”,维基百科 ↩︎
  4. BASIC”,《维基百科》,参见章节“非结构化BASIC ↩︎
  5. 欢迎访问Python.org”,Python软件基金会 ↩︎
  6. Liam Tung, “编程语言Python的流行度,” ZDNet, 2020年11月4日。 ↩︎
  7. 数学与信息学中心 ↩︎
  8. 计算机艺术协会 ↩︎
  9. 该术语的具体创立时间及创立者尚不明确,但其在1970年代进入普遍口语使用,距埃德斯杰·迪杰斯特拉在《结构化编程》一书中发表《结构化编程笔记》一文仅数年之隔。该文收录于奥勒-约翰·达尔等人编著的《结构化编程》(伦敦:学术出版社,1972年),第1-82页。 ↩︎
  10. John Backus 等,《关于算法语言ALGOL 60的报告》,《Numerische Mathematik》第2卷(1960年):106–36页, doi:10.1007/BF01386216。 ↩︎
  11. INTERCAL”, 维基百科 ↩︎
  12. Leo Geurts 与 Lambert Meertens,“编程课程”, 《PAGE》(计算机艺术学会通讯),第19期(1971年):第3页。 ↩︎
  13. Barry Mailloux 等,《关于算法语言ALGOL 68的报告》,《Numerische Mathematik》第14期(1969年):第79–218页, doi:10.1007/BF02163002。 ↩︎
  14. Leo Geurts 与 Lambert Meertens,〈初学者的编程语言设计〉,收录于《算法语言的新方向1975》**,Stephen Schuman 编* (Rocquencourt: IRIA, 1976), 第1–18页。 ↩︎
  15. 埃德斯杰·迪杰斯特拉在其论文《带条件语句、非确定性与程序的形式推导》中独立提出了类似的“并发赋值语句”, ACM通讯 18卷第8期 (1975): 453–57, doi:10.1145/360933.360975。 ↩︎
  16. P. J. Plauger, “《编程语言中的信号与噪声》”,收录于Earl Joseph与John White编著的《ACM ’75: 1975年度会议论文集》*,美国明尼苏达州明尼阿波利斯市,1975年10月20-22日(纽约:ACM出版社,1975年),第216页, doi:10.1145/800181.810322。普劳格是屡获殊荣的科幻作家,同时也是具有深远影响的著作《编程风格要素》的合著者,该书标题呼应了威廉·斯特兰克与E·B·怀特著名的写作指南《风格要素》。 ↩︎
  17. 其先驱可追溯至彼得·兰丁的ISWIM语言套件——这套思想实验语言采用可选缩进,并非为提升可读性,而是效仿数学中的缩进用法。参见P. J. 兰丁《ALGOL60与丘奇λ记法的对应关系:第一部分》,载于《ACM通讯》第8卷第2期(1965年),第89-101页, doi:10.1145/363744.363749。1974年,唐纳德·克努特写道:

    显然,与当今语言略有不同的编程语言将更有利于结构化程序的开发。未来我们或许只会编写小型模块,这些模块通过名称标识,用于构建更大程序。因此,在源语言中表达局部结构时,缩进等手段可能比分隔符更具可行性。

    唐纳德·克努特,《带*跳转语句的结构化编程》,《ACM计算机综述》,第6卷第4期(1974年):261–301页, doi:10.1145/356635.356640。 ↩︎

  18. Kurt Koffka, 《格式塔心理学原理》(伦敦: George Routledge & Sons, 1935), 153页。 ↩︎
  19. Lambert Meertens, B编程语言提案草案, Mathematisch Centrum, Amsterdam, 1981. ↩︎
  20. 雅各布·施瓦茨,《论编程:SETL项目中期报告》,纽约大学库朗研究所计算机科学系,1975年6月修订版。 ↩︎
  21. Lambert Meertens, “咦?B就是‘ABC’,明白了吗?,” B通讯 第4期,CWI,1985年。 ↩︎
  22. 理查德·斯托曼,《GNU宣言》,自由软件基金会,2015年6月2日(原发表于1985年)。 ↩︎
  23. 杰克·詹森至今仍活跃于Python社区,尤其作为MacPython的维护者——该项目是Python在macOS(苹果Mac台式机及笔记本电脑操作系统)上的移植版本。 ↩︎
  24. Python最初为何诞生?”,《Python通用常见问题解答》,Python软件基金会。 ↩︎
  25. Tim Peters,1999年6月4日发布于comp.lang.python消息 ↩︎
  26. 互联网上不难找到提供此类概述的通俗易懂的Python入门指南。相关书目可参见Python维基页面:Python.org的《初学者指南/程序员》。一本无需编程基础的入门教材推荐:April Speight所著《Python速成:Python编程入门指南》(印第安纳波利斯:约翰威立出版社,2020年)。 ↩︎
  27. Python软件包索引”,Python软件基金会 ↩︎
  28. 布莱恩·伊斯特伍德,《2021年十大最值得学习的编程语言》,东北大学,2020年6月18日; Joshua Tresvalles,《求职必备:三大最佳编程语言》,《国际商业时报》,2020年10月27日;及《2021年该学哪种编程语言?十大推荐》,《今日印度》,2020年12月20日。 ↩︎
  29. Python创建者揭秘谷歌内部脚本”, 《eWEEK》,2006年3月6日。自2019年起,该职能由指导委员会接管。 ↩︎
  30. 凯拉·马修斯,《Python突然爆红的6大原因》,《KDnuggets》,2017年7月6日; 吴俊,《Python如何成为热门选择》, 《欢迎来到丛林》,2020年2月20日;以及《2021年Python备受开发者青睐的十大原因》upGrad.com,2021年1月10日。 ↩︎

本文文字及图片出自 The Origins of Python

共有 72 条讨论

  1. Ruby和Go都广泛借鉴了Python,但两者都摒弃了原帖所述的通过迭代实验设计语言的过程——即通过实验来确定开发者会如何体验设计选择。相反,它们各自依赖少数经验丰富的内部人士的判断。“我清楚Python哪些部分优秀、哪些糟糕;无需在采纳想法前征求几十位开发者的意见。”

    或许并非巧合,两者均未能取代Python。Go显然获得了谷歌的强大支持。而Ruby则受益于2005年Java社区对解释型语言的迫切需求——当时尚无语言能像Python那样拥有成熟的社区生态。Ruby恰好处于“实用性强,同时为渴望撰写博客的极客们保留大量技术空间”的黄金地带。

    最后我推测,Amber-Brown的“内置电池”争议和walrus运算符风波,揭示了用RFC/Usenet模式管理Python这类基础设施的局限性。

    1. 十年前曾有观点认为,“设计模式”(四人帮)之所以存在,是因为底层语言(Java等)在功能或表达力上存在局限。

      Go语言充满主观性,而这种特质在很大程度上损害了语言本身——Go循环语义便是典型例证。开发者本应在2009年左右及时修正错误,却反而加倍坚持。直至2022年,他们才重新开启讨论。

      https://github.com/golang/go/discussions/56010

      1. 《四人帮》成书于Java诞生之前,书中未涉及任何Java代码,毕竟该语言当时尚未存在。

        所有示例均基于Smalltalk和C++。

        1. 1984年出版社曾告知我《四人帮》将推出Java版本。于是我联系其中一位作者(暂不透露姓名),当我转述出版社的话时,他几乎把我骂得狗血淋头!

        2. 完全正确!这本书与Java毫无关联。

    2. 当时我们根本不需要这种缺乏即时编译机制和基础垃圾回收功能的低效语言。

  2. 引人入胜的阅读体验,此前并不知晓Python这段历史。关于ABC语言因缺乏版权声明引发担忧的描述尤为耐人寻味——这恰恰映射了生活中诸多场景:开放共享虽是正确选择,却也令人心生畏惧。

  3. > 当物体仅部分可见时,人类视觉系统会根据可见部分的形状推断出被遮挡部分的形态。

    是的,例如当我看到这段代码:

      blah () {
        whatever
        whatever
    

    我便知道代码不完整,存在遮蔽部分。至少缺失右大括号:

      }
    

    但遇到这种情况:

      def blah(x):
         foo
         bar
    

    我无法判断这是否为完整代码,也可能是五千行代码的前三行。

    1. 抱歉,这个例子中“被遮挡”的是什么?

      右大括号被遮挡,所以你无法判断这是完整代码还是五千行中的前三行。同样,后续缩进的代码也处于遮挡状态。

      这两者之间存在可感知的差异吗?

      1. 我们能确定这不是完整内容,因为缺少闭合的}。

  4. 正如世上不存在万能交通工具,真正通用的通用编程语言也不存在;对于特定高度专业化的应用领域,总能设计出更契合该领域需求的定制化语言。

    这让我想起围绕Objective-S的讨论http://objective.st/About

  5. 除了Python之外,还有哪些适合入门的编程语言?

    1. 若想构建网页应用程序和/或网站,请学习JavaScript。

      若想从事底层编程,请学习C语言。

      若想折磨自己…呃,我是说编写和维护企业级应用程序,请学习Java。没错,就是那个。

      1. 关于JavaScript与网页开发的小补充:仅使用服务器端编程(如Python/Django/Flask)配合HTML5构建任意复杂度的网站完全可行。我认为HTML5是JavaScript的有效替代方案。虽然并非所有功能都能通过HTML5实现,但那些无法实现的功能,或许本就不该被实现。

    2. 这取决于入门教学的目的。对于实用编程而言,即便是Excel公式也堪称合理的编程入门途径。公式中的IF条件、数值传递等机制,恰恰体现了基础编程概念。

      一旦掌握编程逻辑,语言选择并非关键。Python固然可行,不过我个人厌恶其严格缩进要求,还总忘记冒号…

      我发现REPL在初学阶段反而增加复杂性。将程序文本置于视野中能更好地掌控逻辑意图。从这点看,编译型语言和脚本型语言并无本质差异。

      根据我的经验,最难教导的部分是将问题分解为逻辑步骤的方法。嗯,这就是分析环节。

    3. Ruby 🙂 关键在于找到契合你学习节奏的入门教程。掌握基础概念后,学习其他语言就容易多了。

      之后的话,我认为更重要的是社区氛围和开发理念——这决定了库的编写方式等等。

    4. 我推荐LISP或Haskell。

      但它们的学习方法与C类语言截然不同。

    5. C语言、JavaScript或其他通用语言都行,关键要有好老师。首选语言的重要性被严重高估了。

      1. 我不同意。应选择无需编译器或复杂配置的解释型语言,如Python、JavaScript这类入门门槛低且具备REPL环境的语言。更理想的是选择能获得朋友或同事帮助的语言——这可能是更大的优势。

        1. 我的第一门语言是C++(偏向C风格的版本),后来深感受益。编译器配置并不复杂(实际上比管理Python/JS依赖更简单)。

          我坚信应给予学习者更多信任——相信他们具备学习能力,而非刻意降低难度。我并非贬低JavaScript或Python,它们同样是优秀的入门语言;我的核心观点在于:应普遍信任初学者具备学习能力,而非过度简化教学内容。

          1. 学习动力源于内在驱动力,而无谓的难度会削弱这种驱动力。因此,通过更易上手的语言学习能取得更佳成效。

            内存管理和类型安全稍后再学也来得及……编程的核心精髓与这两者无关。它关乎抽象概念的定义与组合,这与具体语言无关。

    6. 华盛顿大学曾在Coursera开设过优质的《编程语言》MOOC课程,按以下顺序使用三种语言教学:标准ML、Racket和Ruby。

      1. 这确实让不少新手在我们常用的IRC频道里抓狂。

        我认为基于《如何教导自己编程》的Scheme课程仍是学习“编程”的最佳途径

        1. 我已有超过4年专业软件工程经验(主要从事后端网页开发)。在此之前,我作为业余爱好编程约8年。精通C、Python和PHP,同时熟悉多种其他语言,还略懂Haskell。

          像我这样的人,学《头脑与笔尖编程》值得吗?我之前尝试过但觉得有些枯燥。但我知道这本书口碑很好,所以想知道是否该再试一次。

          还是应该直接读《计算机程序的构造与解释》?

          1. 哎呀,从某种意义上说,《头脑与笔尖编程》是为零基础初学者准备的[0]。《计算机程序的构造与解释》涉及更深奥的主题,我认为你能从中获益更多。不过需要注意的是,书中大量练习基于实数(当时面向电气工程师),有人喜欢这种风格,也有人不适应。

            或者你可以尝试MOOC课程(如果课程仍在开放):EPFL的Scala函数式编程课程(M.Odersky主讲)非常出色。华盛顿大学编程语言课程(D. Grossman主讲)。

            布朗大学CS173课程(与Grossman相关)https://cs.brown.edu/courses/cs173/

            希望你能从中找到乐趣

            [0] 它对我而言的价值在于不拘泥于特定范式,而是以纯粹的方式引导人们构建数据结构,并通过逻辑拆解形成显而易见的函数。它教导的是预先思考,而非先写代码再受苦。基于Scheme的设计更让人领略到极简语言的精髓(闭包与列表)。

    7. 我认为计算机入门最佳途径是汇编语言。

      我实际的入门经历是:先学了几个月Fortran,随后四年转攻IBM 1401汇编器——当你用汇编语言编程时,Fortran的局限性便荡然无存。

      汇编语言能让你从骨子里领悟计算机的本质及其运作机制。

      理解其根基后,你自然能看透所谓高级语言的运作原理。

      顶尖汇编专家会为每个问题领域生成专用领域语言,并拥有庞大的子程序库和现成宏库。我始终坚信:若你真正精通汇编,必将游刃有余。这意味着你掌握着精确的机器知识、正确的思维模式、处理<常见需求>的子程序库,以及实用宏(本质是特化子程序)。

      不过。这适用于小型机器和x86/68k架构;但。面对amd64+架构日益膨胀的复杂性,以及极其繁复的指令集,要精通每条指令的细节以编写优于顶级C语言(甚至可能是Rust)编译器的汇编代码,难度已大幅提升。

      即便你仅使用amd64或arm指令集的子集,也能深刻理解机器实际“运作机制”。

      若你真正痴迷此道,嵌入式领域将为你敞开大门。祝你好运!

      1. 谨记:点踩仅用于标记违反HR规则的评论。若对论述严谨的真实观点存异议,不应点踩。

        此时应回复:并展开讨论。

        一如既往,我坚持自己的观点——这些皆源于亲身经历。我相信它们相当准确,且构成了对提问者问题的深思熟虑的回答。

        例如无人追问我为何苦学四年汇编语言;但容我说明:我曾为名为“Simpletran”的Python类语言编写编译器。该语言比Python早诞生数十年,但早期Python的诸多核心理念皆源于此。

  6. 我认为Python的变迁已使其难以胜任入门语言的角色。

    零基础初学者根本无法理解那些包含装饰器、生成器等复杂概念的普通Python代码。

    概念实在太过繁杂。

    如今它已被惯性选择所困,原初目标用户群体——那些如今在工作中使用它的职业程序员——已将其彻底扭曲,背离了最初的设计初衷。

    1. 庞大的代码库对初学者而言向来难以理解。

      作为入门语言,我实在想不出为何需要用到装饰器、生成器之类的东西?你根本不需要学习控制流、函数、变量等概念。完全可以不用这些花哨的东西写出完美的Python代码。事实上,许多靠写Python谋生的数据科学家,对类这类看似基础的概念都一窍不通。

      1. > 我实在想不通为何需要用到装饰器、生成器之类的东西?你根本不需要学习控制流、函数、变量等概念。

        关键在于,当初学者开始接触“专业领域”时,他们会突然发现自己根本不懂Python——因为他们使用的只是语言的原始子集。

        1. 但哪门语言不是这样?学习任何语言都是循序渐进的,掌握10%的知识并不意味着就能胜任专业编程,这适用于所有语言。

          1. > 掌握10%的知识并不意味着就能胜任专业编程

            我不明白为什么不行。许多人都是在职学习,包括学习新语言,实际工作中你可能会通过拼凑实现某些功能,对具体细节了解甚少,这些细节往往需要后期系统学习。我经常这样做。

          2. > 但哪门语言不是这样?

            Go语言,但它又带来了另一套棘手问题

          3. 掌握多少知识才能专业使用一门语言?

        2. 以C语言为例。仅数百页的C语言规范足够简洁。它没有装饰器、模式匹配、lambda表达式等花哨特性。

          但编程三十年后,我真算懂C吗?一旦深入研究C编译器、未定义行为等领域,我很快就能说服自己其实根本不懂C…

        3. 但你总是从使用语言的原始子集开始。

        4. 但这太令人兴奋了!更多前沿领域等待探索!!

    2. MicroPython或CircuitPython已成为比完整语言更理想的入门选择。

      Python日趋成熟,被广泛用于解决诸多复杂重要的问题。这使得该语言不仅优秀,甚至堪称解决这些问题(如数据科学)的绝佳工具。其中或许有些浮夸之处;但大部分特性可能与你惯用的风格或问题领域无关。

      1. 对于专业Python程序员而言,这些变更或许值得欢迎。逐步跟进新增特性总比一次性消化所有更新更轻松。C++同样存在此问题,但它的卖点从来就不是易用性。

        1. 我正是担忧Python走向的人——这个曾经相当易学的语言正步入C++的后尘,终将被考古层般的冗余代码与晦涩逻辑所埋没。

          2.x与3.x版本在哲学理念上似乎渐行渐远,我并不认为这是好事。

        2. 1990年代的C++简单到高中生都能掌握。

    3. > 零基础初学者根本无法理解带装饰器、生成器等元素的普通Python代码。

      作为同时教授Python和其他语言的初学者导师,我认为教装饰器比教高阶函数要容易得多。因为在Python教学中,学生们在接触“函数返回函数”这个概念前,早已通过缓存装饰器亲身体验过其作用机制——而这个概念无论在Python还是其他语言中,都需耗费时间才能真正领悟。

      至于生成器,我从未见过有人为此困扰。你觉得生成器的哪些方面难以理解?

      1. 生成器对资深开发者都存在几处陷阱:调用 len(mygen) 或 mygen[4] 虽能正常工作,但后续迭代时却会发现内容为空。尤其棘手的是当有人添加生成器内容日志时,会在使用前耗尽生成器。这些问题导致人们习惯性地对所有生成器使用 mygen=list(mygen) 操作,却不理解其真正含义。

        如何解决这个问题我也不太清楚。生成器作为如此有用的概念,既无法真正移除,又需要保持与其他列表和可迭代对象的兼容性。即便使用类型提示,在编写代码时也难以明确区分某个变量是生成器还是具体列表——它们大多遵循相同的协议。

    4. 零基础初学者无需接触带装饰器的普通Python代码。Python作为教学语言的精妙之处在于:编写简单的字符串数字输入输出程序时,完全无需解释或模糊处理这些复杂特性——仅此就足以教授条件语句、循环、函数等基础概念。更妙的是它开箱即用的海龟图形功能,能直观演示递归等高级概念。

      当学员通过基础练习掌握核心概念后,才需要讲解装饰器、生成器等进阶内容。此时他们无需转换语言环境——所有已掌握的基础知识仍能完美适配新场景。

    5. 我依然钟爱交互式解释器。它堪称绝佳的无障碍教学工具,尤其适合现场演示基础概念并即时反馈。在向我九岁的女儿讲解那些难以言传的概念时,它成了不可或缺的利器。

    6. 这些概念其实在过去二十年里早已存在于语言体系中。

    7. 易用性与易学性往往与性能相冲突。

      卡丁车比一级方程式赛车更容易上手驾驶。

      1. 顶尖车手往往从卡丁车起步,这种对路面的感知能力,以及在有限车辆中发挥极致性能的经验至关重要。

        我不会把Python比作卡丁车,更像是厢式货车——虽然平淡无奇且常遭轻视,却是日常通勤的最佳选择。

      2. 投入资金/时间/精力有时能改变局面。例如如今JavaScript和PHP在特定工作负载下表现相当出色。

    8. 我始终认为Python并非理想的入门语言。它过于抽象,隐藏了其他语言常需显露的细节(Python的灵活性实在太强)。若仅用于脚本编写或调用库API,它确实值得学习;但若目标是转向C++这类结构更严谨的语言,Python绝非理想起点。

      1. Python之所以是理想的学习语言,恰恰在于它隐藏了这些细节。这使得人们能够专注学习变量、循环、字符串等基础概念,避免被过多知识点同时淹没。

        这种学习方式为后续掌握底层概念奠定了良好基础,尽管自下而上从C语言等开始学习也是可行的路径。

        值得注意的是,多数开发者终其职业生涯都不会接触C++,始终专注于高级语言。还有一部分人则会在积累多年经验后,才开始学习底层技术。

        你的目标是立即成为C开发者,那么学习C是必然选择——但这并非大多数编程学习者的初衷。

        1. >>> Python之所以是理想的学习语言,恰恰在于它隐藏了这些细节。这使得学习者能专注掌握变量、循环、字符串等基础概念,避免被过多知识淹没。

          这种特性究竟是福是祸,或许取决于学习者本身。以我为例,1981年接触的第一个语言是BASIC,因此每当讨论编程语言时,我总会下意识觉得BASIC至少能让人想象运行程序的机器如何运作——老师可以在黑板上画方框解释10行代码LET X = X + 1

          当时我们离机器很近,从逻辑门层面往下看,中间没有太多“乌龟”。高中时我还通过阅读书籍和《字节》杂志文章学习了微处理器的工作原理——这些内容放在当今庞大的CPU面前简直可笑。

          这是自下而上的方法。对其他人而言,自上而下或许更合适——比如欣赏数学方程在优美符号中展开的过程,无需在意机器底层的运作机制。

          本讨论中另有人提及代码阅读能力。Python已发展得过于庞杂。我作为“科学”程序员用Python编程十年,最近参加技能测评时指导新手, 然而我的成绩仅勉强达到“平均水平”。许多复杂的Python包中的代码,我已无法看懂。

          问题在于:当人们知道自己终将超越某种语言时,如何激励他们去学习这种语言?

          1. 我不太明白Python相比BASIC缺少了什么。

            当然,你可以教学生写print(“ ”.join(str(x) for x in range(1, 11)))来打印1到10的数字…但其实没必要这么做。事实上,X = X + 1完全可行。老派BASIC风格如X = 1; while X <= 10: print(X); X = X + 1在Python中依然有效。(抱歉未保留缩进)

            我漏掉了什么?(除了那种误导性的社会期待——认为必须向零基础初学者灌输花哨的生成器概念…)

            1. 这是个好问题。我脑海里浮现的(暴露年龄了)更像是这样的代码:

                  10 LET I = 1
                  20 PRINT I
                  30 LET I = I + 1
                  40 IF I <= 10 THEN 20
                  50 PRINT “DONE”
              

              正因BASIC如此原始,你无需太多虚构就能解释每行代码的作用。虚拟机在思维中与真实机器并无本质差异。

              老师会用粉笔和橡皮擦在黑板上画出装有数字的方框来表示变量,实时更新数字(这更暴露了我的年龄)。

              相比之下,Python从*万物皆对象,具备属性和方法…*的理念起步。

              不过我认同关于花哨生成器的观点。我认为通过限制教学内容只涵盖少数基础特性,同时采用相同的虚拟机概念(但需提醒学生这比现实抽象了数层),同样能用这种方式教授Python。

              1.   40 IF I <= 10 THEN 20
                

                这是否意为“跳转到20行”?若非如此,该语句要么毫无意义,要么暗含需解释的“魔法”跳转指令。若将其视为循环,Python的等效实现其实不难理解:

                  i = 1
                  print(i)
                  while i <= 10:
                    i = i + 1
                  print(“DONE”)
                

                代码行数相同,while的含义比你那行无goto的魔术代码更清晰,甚至比goto版本的控制流更易理解。唯一缺失的是显式行标记,但这在讨论代码时可作为展示格式。任何面向初学者的编辑器都能显示行号(多数默认显示)。

                教学无需从“万物皆对象”切入,但很快会自然过渡。对合格教师而言,以数字字符串和Python基础控制流为核心的程序化编程教学并非难事。随着学习者对计算与编程的理解深化,语言本身也能随之进阶。

                1. 确实,GOTO语句是隐含的。在THEN之后添加其他内容是后来才出现的,while循环也是如此。

              2. 属性确实会改变数据表示形式,但i.print()其实并不比print(i)更复杂。

        2. 学习过程中隐藏细节固然重要,但Python的抽象化做得过头了。for循环和基于迭代器的循环被合并为一种形式,我敢肯定很多人写for i in range(10)时根本不理解range函数的实际作用。甚至字符串也模糊了单个字符与实际字符串的界限。正是这些基础概念的模糊性,使得Python不适合作为初学语言——它刻意隐藏了其他主流语言普遍存在的概念。结果我常看到学生养成不良编程习惯,对代码运行原理形成错误认知。他们只掌握Python提供的语法糖和抽象概念,却未能真正理解正确的编程原理。

          我承认Python确实提供了极低的编程入门门槛,但这是以牺牲细节为代价的。这种特性或许有助于激发兴趣、产生动力,快速实现原型或“Hello World”程序——但学习Python仅适用于学习Python本身,而非掌握通用编程技能。

          1. 坦率地说,经典C风格的for循环对初学者而言是糟糕的抽象。迭代器循环在高层次上合理(“我不在乎实现细节,只关注功能效果”),而while循环在低层次上合理(“我能看清每个部分如何运作”)。对初学者而言,C式for循环不过是while循环的晦涩隐式语法。

            > 甚至字符串也模糊了单个字符与实际字符串的界限

            我认为这比C的做法更合理——C假装字符是单字节存储。而当今多数代码使用Unicode编码,一旦尝试存储非ASCII字符就会导致代码崩溃。

          2. 若能理解“for i in”的含义,range就不会太难掌握。我认为即使是刚接触编程且具备基本逻辑思维的人,也能轻松猜出range的作用。

          3. 范围对初学者而言简直是噩梦。试着向学编程的孩子解释:为什么乘法表程序要写成range(1,13)?这种构造确实有其合理性,半开区间也值得推荐,但为孩子提供友好入门体验绝非其考量因素。

      2. 我为你点赞,尽管观点有误,但切中了要害。

        若教初学者,我会安排1/3的Python作业和2/3的C语言作业。

        他们需要在起步阶段获得些轻松的成就感,同时掌握控制流和基础概念。但在此过程中,我们也会穿插C语言教学,让他们理解底层机制。

        这种“轻松胜利”至关重要。记得入门课时,我们只需复制C++代码编译,明明感觉完全照抄了,却收到一堆莫名其妙的错误提示,整个人彻底崩溃。

        当时觉得无论怎么写都行不通,完全提不起兴趣,最终直接退课了。

        直到多年后用Visual Basic做项目,才发现编程原来可以这么有趣。

      3. C作为入门语言过于庞杂,现代C尤其在STL加持下更隐藏了大量细节。

        不妨选择C++子集教学,或直接教授C语言(我更倾向后者)

  7. 有位Python初学者花了五年才掌握Python。

    这正是我朋友多年前尝试转行编程时的经历。

    而一位JavaScript初学者仅用半年就掌握了后端API、桌面端、移动端及Web应用开发,甚至迅速掌握了SQL。

    我认为原因在于更深层的文化认知:他认定Python是唯一需要掌握的语言,其他语言皆可有可无。

    1. 这两者似乎是截然不同的个体,或者说他们选择了完全不同的学习材料/导师。Python和JS在这方面的差异几乎不存在,除非它无法(直接或至少不易)作为网页应用的前端(在浏览器中)使用。

      > 我认为原因在于更深层的文化因素:他认为Python是唯一需要掌握的语言,无需学习其他技能。

      问题就在这里。这并非Python“文化”使然,而是他个人的问题(当然不止他一人,许多人都会陷入这种误区)。我见过太多同事对C、C++、JavaScript或<他们偏好的语言>深信不疑,却对其他语言一窍不通或仅有浅薄了解。他犯了错误,这很遗憾。若能获得导师指导(或现有导师更出色些)本可避免。真正的程序员都明白:除涉及可用的库或运行平台外,编程语言本身往往无关紧要。

      1. 这让我思考了很久。因为当我选择一种语言来教新手/学生时,避免让他们因文化差异而陷入陷阱对我来说至关重要。新手与经验丰富的程序员不同,后者深知语言只是工具。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: