循环语句中else子句的灵感与影响?
在Python中,循环语句可以有一个else
部分,这个部分只有在循环没有被break
终止的情况下才会执行。换句话说,就是当条件变成False
(在while
循环中)或者当迭代器用完了(在for
循环中)时,else
部分才会被执行。
这种循环加else
的写法是源于其他语言吗?不管是理论上的还是实际实现的?有没有被新的编程语言采用呢?
也许我应该问问Guido,但他肯定太忙了,不会理会这种无聊的问题。;-)
相关讨论和示例: 在for循环中使用‘else’的Pythonic方式
2 个回答
我刚刚在这个更广泛的问题的评论中发现了一个很不错的线索。用户ΤΖΩΤΖΙΟΥ写道:
有人还记得Sinclair QL的SuperBasic中的FOR var … NEXT var … END FOR var吗?在NEXT和END FOR之间的所有内容都会在循环结束时执行,除非发出了EXIT FOR的指令。那个语法看起来更简洁 :)
网上有一份Sinclair QL用户指南的OCR版本。里面写道:
NEXT语句可以放在循环中。它会让控制权转到紧接着FOR或REPeat关键字后面的语句。可以把它看作是EXIT语句的一种反义词。巧合的是,NEXT和EXIT这两个词都包含EXT。可以把它想象成对循环的一个扩展:
- N代表“现在重新开始”
- I代表“结束了”
接下来是一个有趣的例子:
警长有一把装了六发子弹的枪,他要对准强盗开枪,但还有两个条件:
如果他打中了强盗,就停止开枪,返回道奇城。
如果在打中强盗之前子弹用完了,他会告诉他的搭档看住强盗,而他(警长)则返回道奇城。
100 REMark Western FOR with Epilogue
110 FOR bullets = 1 TO 6
120 PRINT "Take aim"
130 PRINT "FIRE A SHOT"
140 LET hit= RND(0 TO 1)
150 IF hit = 1 THEN EXIT bullets
160 NEXT bullets
170 PRINT "Watch Bandit"
180 END FOR bullets
190 PRINT "Return to Dodge City"
所以,在一种不同(而且可以说是更不令人困扰)的语法下,它的意思是完全一样的。
维基百科告诉我们,Sinclair QL于1984年2月推出,是Sinclair ZX Spectrum的继任者,但未能取得商业成功。
在Common Lisp中,有一个类似的功能叫做LOOP宏,彼得·赛贝尔在这里描述过:
...LOOP提供了两个关键词,initially和finally,用来引入在循环主要部分之外要执行的代码。
在initially或finally之后,这些部分包含了所有的Lisp代码,直到下一个循环部分的开始或循环的结束。所有的initially代码会被合并成一个开头部分,这个开头部分会在所有局部循环变量初始化后立即执行,并且在循环主体之前运行。finally部分也会被合并成一个结尾部分,在循环主体的最后一次执行后运行。这两个部分的代码都可以使用局部循环变量。
开头部分总是会执行,即使循环主体的迭代次数为零。如果发生以下任何情况,循环可以在不执行结尾部分的情况下返回:
- 执行了一个返回语句。
- 在循环主体的Lisp代码中调用了RETURN、RETURN-FROM或其他控制转移的构造...
例如,链接问题中找到的部分Python示例:
for v in known_variables:
if self.bindings[v] is cell:
return v
else:
raise CannotSimplify
可能看起来像这样:
(loop for v in known-variables
when (eq (gethash v (slot-value self bindings)) cell)
do (return v)
finally (signal cannot-simplify))
还有一个观察:
Common Lisp的条件系统也很独特。曾经有人问它的来源,结果被指向了肯特·皮特曼的论文,他提到这个系统来源于Maclisp。同样,Common Lisp中看起来奇怪的FORMAT函数显然是通过丹·温雷布引入的,来源于Multics。
共同的特点是,语言的特性往往不是直接来自于最初启发这门语言的祖先语言,而是由那些喜欢这些特性的人带到他们正在开发的新语言中。因此,如果你想找出Python的for
-else
的实际来源,我建议你去查查是谁添加的,然后看看他们之前使用的是什么语言。