当前位置: 首页 > 后端技术 > Python

编程语言问题:什么时候借用什么时候创建?

时间:2023-03-26 19:37:30 Python

6月22日,Python之父Guido在推特上发布了一段关于Python的历史故事。他说elif是从C语言偷来的。elif是elseif的缩写,用于条件判断。当只有两个分支时,我们会写“if...else...”,当分支较多时,我们会写成如下格式:if判断条件1:Dosomething1elif判断条件2:Dosomething2else:Dosomethingelse得到的elif不仅节省了几个字符,而且由于其目的单一明确,不会给我们带来理解或使用上的混乱。不过缩写不是主流,完整写法才是主流。在C语言中,完整的写法是:if(判断条件1){dosomething1}elseif(判断条件2){dosomething2}else{dosomethingelseThings}没错,C语言使用全拼,但在其预处理/预编译语句中,还有一条elif指令,这就是Guido的“窃取”来源:#if常量表达式公式1//编译1#elif常量表达式2//编译2#else//Compile3#endifPython没有预编译,所以所谓的窃取与预编译无关,只是比较了两种写法,借用了更简洁的写法而已。为什么C语言不统一这两种写法呢?这个我就不知道了,Guido在两种写法中选择了后一种非主流但是比较好用的写法。我要告诉他,你“偷”得好!其实留言区的人也有同感,表示:不介意,没事,很喜欢,还有人说“不是偷,是收割”“不是偷窃,但它已经上升到一个更高的层次。”...print这个词是从C语言借来的。另外,如果有人仔细比较两种语言的关键字和惯用命名,他肯定会发现很多相同的内容。编程语言之间有一些共同的元素.这个很常见,创造一门语言并不意味着创造每一个词和句子,毕竟大多数思想都是共通的,尤其是作为基础设施的词我应该什么时候创建?这个问题可能看起来没有实际意义,因为我们大多数人不太可能在我们的一生中参与创建一种编程语言。但我认为它仍然非常有意义。首先,质疑精神是值得的其次,它也提供了系统的溯源、筛选、选择、创造的视角,我认为这才是求知的正确思路。带着这个疑问,我特别想研究一下Python的for循环。如果有其他语言基础,就知道“for循环”通常指的是这种三阶段结构:for(init;condition;increment){statement(s);}//javafor(intx=10;x<20;x=x+1){System.out.print("x的值:"+x);System.out.print("\n");}这种C风格的写法很初级,很多语言都借鉴过。但是,它的写法实在是太繁琐了。为了更方便地遍历集合中的元素,人们在for循环之外还引入了升级版的foreach循环://javaint[]a={1,2,3};for(inti:a){System.out.print(i+",");}//C#int[]a={1,2,3};foreach(intiina){System.Console.WriteLine(i);}Python也有for循环,但大量借鉴,在设计上有其独特的考虑。它直接摒弃了三段for循环,采用了类似foreach的写法:foriterating_varinsequence:statements(s)#Exampleforiinrange(3):print(i)foriin"hello":print(i)从表面上看,Python的for循环与其他语言的foreach非常相似,但实际上,它的工作方式非常不同。为什么有什么不同?主要是因为Python的for语句是用在可迭代对象上的,而不仅仅是用于集合或普通容器(虽然它们也是可迭代对象),而可迭代对象又可以细分为迭代器和生成器,这会在最终结果上产生巨大的差异。先看两个例子:#例子一,普通的可迭代对象x=[1,2,3]foriinx:print(i)foriinx:print(i)#例子二,迭代器或生成设备y=iter([1,2,3])#y=(iforiin[1,2,3])foriiny:print(i)foriiny:print(i)Example1,"123"将打印两次,而在示例2中,它只会打印一次。普通的可迭代对象只有__iter__()魔术方法,不像迭代器有__next__()魔术方法,这意味着它无法实现自遍历过程,遍历for循环原结构后不会被销毁.但是迭代器是一种稀缺设计,具有单向丢失的特性,遍历一次就会被销毁,不能重复使用。由此可见,Python中for循环的使用范围很广,也可能带来不纯的结果,即重复执行同一个代码块会产生不同的结果。这与其他语言有什么不同吗?同一个关键词,类似的循环思维和写作,但产生的影响是不同的。关于Python的for循环,还有一个很独特的设计,就是for-else结构:x=[1,2,3]foriinx:print(i,end="")else:print("ok")#Output:123ok本文开头提到的if-else结构。只有当if条件不满足时,else部分才会被执行。也就是说,如果if语句为真,其语句块执行完后,else部分将被跳过。这是一种非此即彼的平行关系,字面意思是“如果……那么……;否则……”。但是对于for-else结构,for语句并不是在做真值判断,它的程序体是必须要执行的(除非可迭代对象为空),执行完之后else部分会继续执行。因此,是first、then、then的串联关系,翻译为“for……then……;andthen……”。这个结构绝对不是从C语言里借来的。至于它最初是否是由Python创建的,我不确定(很有可能是,让我认为是)。如果有知道的同学麻烦告知一下。那么,Python为什么要加入这样的设计,有没有实际用途呢?x=[1,2,3]foriinx:ifi%2==0:print(i)#matchbreakelse:print("mismatch")上面例子的for部分增加了判断和break,这样break不仅会跳出for循环本身,else部分也会被跳过。上面例子的作用是找一个偶数,找到了就打印出来。如果for循环后找不到,就进入else分支,打印“不匹配”的结果。所以,其实else就是for循环是否有正常的遍历结束标志。如果循环后没有达到某个目标而跳出(break,returnorraise),可以在else中进行必要的添加(logging,throwingexception等)。这种设计不是一个好的设计,因为else会引起误解(if-else那种非此即彼的关系),它的最大使用需要结合break等操作跳出循环,但是这一层信息是不明显的。在核心开发者的邮件列表中,有很多争议点。其中,有开发者建议:去掉这个写法。如果不写break,会产生报警提示,替换else关键字(如then,finally,elsenobreak),增加其他功能。这封邮件一一列举了这些观点的理由和改进想法,然后一一反驳。最后的结论就是保持for-else的写法不变,也就是你现在看到的实现方式。其完整的语义是:如果到达`break`执行for循环(或while循环),跳转到`for...else`块的末尾else执行`else`套件,即else目标是“是否执行break”,如果没有break,则进入else。但是,我不同意这种做法,因为break是一个隐含的条件。直观上我们只看到for-else,很容易产生if-else这样的联想。因此,我改为同意将else更改为then以消除误解。这封电子邮件中的反驳论点是,更改为then会引入一个新关键字,因此并不好。我觉得这个说法有点牵强(站在用户的角度),记住本文开头的内容,elif是新引入的关键字,看看现在流行到什么程度。elif是那些你乍一看不认识的单词之一,但当你知道它时你肯定会记住它,而且你不太可能拼错它。为了简洁和易于拼写,它被引入为一个新的关键字。for-else中的else属于那种乍一看觉得有意义的词,实际上表达的是不同的意思(准确的说是不知道隐含条件造成的误解),为了清楚语义上,我认为可以引入一个新的关键字then来代替else。但是,我改变了主意,认为现在讨论这个没有意义。毕竟时过境迁,都是10年前的事了。如果这个讨论是在Python创建之初,或者在Python3的重大变化之初提出的,那么很可能for-else会被设计成for-then,然后像elif关键字一样被引入。如果真是这样,说不定哪天圭多心血来潮说起这段历史小故事,评论区就会有一大堆赞同的声音。说到这里,话多了,不过好像有点跑题了,总结几个重点吧:Python从C中借用elif,赞不绝口。Python并没有借用C。传统的三段式for循环。但它的应用范围更广。由于迭代器的设计,Python的for循环会造成一些陷阱。Python创造了for-else结构,它的隐含语义是for-(ifbreak)-else。关键字来替换for-else,但被拒绝了。这篇文章的内容很少,似乎没有什么实际帮助。不知道elif的出处,不知道for循环的细节,不知道for-else的使用和争议,这些都不会造成语言障碍。但我还是有那个观点:读一读Python的历史,从中可以看到设计者打磨功能细节的过程,最终明白Python是如何一步步发展到今天的。以上就是本次分享的全部内容。想了解更多python知识,请前往公众号:Python编程学习圈,发“J”免费领取,每日干货分享