Python 为什么如此设计?

2022-12-19 08:04:11 +08:00
 chinesehuazhou
分享一篇文章: https://zhuanlan.zhihu.com/p/592658877



涉及 Python 语法设计、发展历史、编程思想等话题。
10859 次点击
所在节点    Python
81 条回复
penguinWWY
2022-12-19 11:45:58 +08:00
不少都是强行找理由
某些问题就是设计的菜或者个人口味问题
MoYi123
2022-12-19 11:50:53 +08:00
@urnoob 已经开了几十年了, 怎么还没消失?
seakingii
2022-12-19 11:51:57 +08:00
我对 python 的语法 没有意见,有意见的是性能低和部署麻烦,其它方面很喜欢
chinesehuazhou
2022-12-19 12:06:59 +08:00
@msg7086 提出不同意见容易,再补充论据支撑观点困难。建议你补充,否则可以认为你的留言毫无意义
chinesehuazhou
2022-12-19 12:15:47 +08:00
@aloxaf 文章提到 4 个原因,前三个关于优劣,“世界本质的洞察”是我个人的发挥,不代表设计者的观点。但是,我还是愿意强行拔高,因为我需要找到一些文字来表达自己对这种设计拍案叫绝的情绪。就像足球迷愿意说梅西“封神”了,啥,没感觉的人可能质疑,取得再好成绩也不至于扯上“封神”吧……
chinesehuazhou
2022-12-19 12:22:13 +08:00
chimission
2022-12-19 13:11:38 +08:00
不管认不认同, 能把自己的观点整理成本章写出来就很棒。表达观点很简单,但是论证观点却很难
FrankHB
2022-12-19 13:59:03 +08:00
@aloxaf 口味问题严重到一定地步,还真可以说明对世界的本质缺乏洞察力。比如看看这里 GvR 是怎么认怂的:
http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html
作为对比,这方面什么叫有洞察力的:
https://www.researchgate.net/profile/William_Clinger/publication/2728133_Proper_Tail_Recursion_and_Space_Efficiency/links/02e7e53624927461c8000000/Proper-Tail-Recursion-and-Space-Efficiency.pdf
注意考察这里的分析对具体(任何允许递归函数调用的)高级语言的具体设计基本中立。
设计通用语言的有义务理解计算模型和理论 CS 教育的影响。MIT 的某课程改用 Py 在这方面就是一种消极的影响,尽管这锅不是 GvR 背的,但没有 GvR 瞎搞,这个世界恐怕会好很多。
倒不是说 GvR 多大奸大恶,但是一个平庸的选手占据了过于显著的地位浪费资源引领菜鸡互啄,这是业界的不幸。

当然这文章里提到的东西普遍比较水(作者的洞察力相当可疑)。
比如什么 i++,根本就是 artifact ,该问的是本应当是为什么 C 之流使用这种设计,而不是 Python 不使用这种设计。Ken Thompson 搞出这货的时候还有节约代码长度的技术作用(类似的一个更著名的语法是 C 的声明符),现在剩啥? Python 没有稀里糊涂照抄这种设计,反而是正常人的思路。
这里唯一跟“本质”洞察力能扯上关系的是 lambda 的设计(其它大都是比较菜的历史和工程 tradeoff 问题)。这个例子中,社区里脑子正常的更多点,比 GvR 更加分得清限制的工程复杂度后果;不过半吊子妥协搞得不伦不类也许是更差的结局。当然,这点也说明“由个人主导的语言”早就寄了。不过如果让这 BDFL 一路作死,说不定现在就没那么多不求甚解的口味奇怪的用户了。
aloxaf
2022-12-19 14:09:44 +08:00
@chinesehuazhou #25 我认为能够让人拍案叫绝的,应该是足够巧妙的设计。len 这种东西我认为完全是受过程式思维的影响(当然并不是说过程式就是落后的),一堆脚本语言都是这么干的,不足以称之为巧妙。
aloxaf
2022-12-19 14:21:48 +08:00
@FrankHB #28 嘛,对于早期的语言设计者应该要宽容一点,毕竟他们是趟坑的人,而我们是站在巨人肩膀上的人(除非是在 21 世纪还在以 70 年代的思维设计语言
FrankHB
2022-12-19 14:43:04 +08:00
@aloxaf len 这种东西说不上多巧妙,但是现实中几个值得一提展开的点(还是普遍到跟 Python 不需要直接关系)。
我确信 GvR 始终没摸到这方面的坑的主要边界,以至于解释中很大程度都是 ABC 的历史包袱。

1.关于混合所谓自由函数和方法的问题。
其实大多数语言都还没有复杂到要你纠结坑的地步,但也存在进退失据的例子。搜索 C++ UFCS 有真相。
因为,认为 len(x)和 x.len()不是一种含义会造成明显的不一致,以至于有不少人认为这两种语法的含义干脆合并得了,定义一个就能两用。但这样就有个灵魂拷问:既然允许 len(x),为啥还要发明 x.len(),浪费一个不同的语法?然后什么 customization point 之类的妖魔鬼怪上来凑一脚,不忍直视……
所谓“前缀符号更可读,简单胜过复杂”其实倒并非没有道理。
仔细还原这类语言的语义规则,*this 被作为隐藏的参数,但这其实还有个更一般的形式——静态环境(在静态语言中通常被处理成不可见的符号表)。
隐藏显式名称查找的语法,都写成前缀,比如 Lisp 语法:(len x)——就能发现完全是一回事。是不是要依赖 this/self ,只不过 len 到底是从哪里来的罢了,这完全可以作为实现细节,而实现这里的简单。

2.这玩意儿是个普遍的问题,和 OOP 本没多大关系。
扯上 OOP 的关系,大约是某 PL 大手子的功劳。
这样的理解原则上就是歪的,应当予以纠正: https://stackoverflow.com/a/74375048

无论是误会的形成还是传播,去除脏话以后,拍案叫绝的成分都是够多的。

顺便,至于 0 索引,那倒是有点洞察世界的味道,但是只字不提 EWD831 ( https://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD831.html )这种常识性文献,多少有点过分。
原文评论区有人指出了这点。GvR 只是提供了关于 slice 的新发明,然而除了提了一点避免 off-by-one 错误问题外并没有涵盖 EWD831 的内容。
EWD831 距离所谓的世界的洞察也是有一段距离的,因为它只是很隐晦地顺带提到了根本原因:基数(cardinals)和序数(ordinals)的区别。
这种洞察,对有点数学(哲学)系统训练的用户来说,实在过于基础了,也许不值一提。不过放在这种文献中解释,从一般情形(而非举例)证明为什么索引应该从 0 开始,本应当是有必要的。不过作者并没那么做。
msg7086
2022-12-19 14:56:28 +08:00
@chinesehuazhou #24 只因 提出了意见而没有补充论据就说留言毫无意义的话,建议阁下只发表在国际期刊上,而不是普通人都可以发言的论坛上。我认为本论坛并没有要求回帖者进行大段论述的要求。

其次,我的个人观点就是阁下在强行升华,或者我换种说法,是把一个没有什么意义的东西强行赋予了意义,或者我换种阁下用的说法,「你的强行升华毫无意义」。

我也可以像阁下一样,去把其他语言吹嘘一番。比如我日常使用的 Ruby ,吸取了 lisp perl smalltalk 的精华设计,用对象+消息的方式来调用功能,还融入了方便好用的正则处理和函数式表达,你 Python 杂乱无章的设计,只能单行的 lambda ,满地的 self ,也好意思拉出来秀设计?

我这么说完下面肯定一堆喷我是傻逼的,对不对。

论坛混了那么多年了,我年纪也大了,放到十年前我肯定来和你大战几十回合,不到天亮不罢休。现在我也就吐个槽,看过的就让他去了。你把 Python 吹得再好或者再差,人们心中自有评判,觉得他设计成神的人也不会改变,觉得他设计成一坨的人也不会改变。反正到最后,工资给得高的公司和职位,不都是写 Java 的么 ┓( ´∀` )┏
FrankHB
2022-12-19 14:58:40 +08:00
@aloxaf 如果是设计 ABC 那时候的 GvR ,那么是可以宽容一点。但设计 Python 的 lambda 的 GvR ,已经不太能那么让人宽容得起来了。说得严厉一点,就是德不配位。
我举的有洞察的对照例子,也都是年代明显更早的论述。
真心要称赞的话,大概 GvR 就一点做得比较突出:没有直接乱缝合别家设计。虽然很多设计拉胯,来源基本上是他自己(比如大多数 PEP 的质量相对无理的原始设计,质量看上去都算好的),那么就不至于稀里糊涂搞得大多数人最终都不清楚为什么要有 i++之类的情况,纠正起来也容易得多。
chenqh
2022-12-19 15:11:55 +08:00
python 最大的问题,还是一开始是单人项目,没有 jit,现在 c 库多了,jit 不好搞了
cc666
2022-12-19 15:39:18 +08:00
看完这段话

> 回到前面的问题:为什么是 len(x) ,而不是 x.len(x),这根源于 Python 的什么设计思想呢?

> Python 之父 Guido van Rossum 曾经解释过这个问题( #TODO: add link ),有两个原因:

>> 对于某些操作,前缀符比后缀更好读——前缀(和中缀)表示法在数学中有着悠久的历史,其视觉效果有助于数学家思考问题。我们可以简单地把公式 x*(a + b) 重写成 x*a + x*b ,但同样的事,以原生的面向对象的方式实现,就比较笨拙。

>> 当读到 len(x) 时,我就 知道 这是在求某对象的长度。它告诉我了两点:返回值是一个整数,参数是某种容器。但当读到 x.len() 时,我必须事先知道某种容器 x ,它实现了一个接口,或者继承了一个拥有标准 len() 方法的类。我们经常会目睹到这种混乱:一个类并没有实现映射( mapping )接口,却拥有 get() 或 keys() 方法,或者某些非文件对象,却拥有一个 write() 方法。

> 解释完这两个原因之后,Guido 还总结成一句话说:“I see 'len' as a built-in operation ”。这已经不仅是在说 len() 更可读易懂了,而完全是在拔高 len() 的地位。

> 这就好比说,分数 ½ 中的横线是数学中的一个“内置”表达式,并不需要再实现什么接口之类的,它自身已经表明了“某数除以某数 ”的意思。不同类型的数(整数、浮点数、有理数、无理数...)共用同一个操作符,不必为每类数据实现一种求分数的操作。

> 优雅易懂是 Python 奉行的设计哲学 ,len() 函数的前缀表达方式是最好的体现。


我概括为:为什么前缀 python 的前缀 len()比后缀 len()更好呢,因为 python 的创始人认为前缀更好(原因有二),所以“I see 'len' as a built-in operation ”,所以 python 中的 len() 函数的前缀表达方式是最好的体现。

这就像:为什么我的回复是最好的回复呢,因为我这个回复的作者觉得自己的回答字数多,因为我舍得多花几个铜币,所以我就是最好的回复这种荒谬的自证一样,牛头不对马嘴。这可能不是完全的自证,但颇有自证的味道。这种文笔。甚至我一度怀疑我阅读理解能力出现了下降。

然后还“I see 'len' as a built-in operation ”,自证的同时,还强行升华了下 len()为哲学,拔高 len() 的地位。其实我对 python 是不反感的,每门语言都有自己的独到之处,但是这种自证和强行升华。

我要是自定义 class ,我绝对还会再选择实现.len()函数
chinesehuazhou
2022-12-19 16:22:57 +08:00
@msg7086 并非想引战。我可能有盲区导致眼界不广,只看到一个设计觉得很赞就说出升华的话。所以才想请教为什么你会觉得它很一般。你最初的语气让人不爽。但我还是想看到一个对于 len () 的友善的有理据的补充
chinesehuazhou
2022-12-19 16:37:22 +08:00
@aloxaf “巧妙”有抖机灵炫聪明的危险倾向。我不会认为 len 是巧妙的。它就简单直观,就是呈现本来事物的本来面目的那种简单,而不是引入模式化、附加非常多基础概念的设计
janus77
2022-12-19 16:50:23 +08:00
还是发到推广节点吧……
DOLLOR
2022-12-19 17:37:23 +08:00
关于 len(arr) vs arr.len()这个,如果只是单独一句表达式的话,它俩就没啥区别。
但如果是一长串的话,比如 a(b(c(d(e(f(g))))))与 a.b().c().d().e().f().g(),后者肯定比前者更清晰。
所以我比较期待能有类似管道符一样的方式,把函数名称后置,比如 arr |> len
chinesehuazhou
2022-12-19 18:04:06 +08:00
@janus77 谢谢建议,但 Python 就是最合适的节点

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/903396

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX