len(x) 击败 x.len(),从内置函数看 Python 的设计思想

爱学习,勤思考;学数学,玩魔术。欢迎点击头部蓝字关注MatheMagician,这里有你要的奇迹!


导语:

除了纯粹的数学和魔术,程序员也是本公众号服务的群体之一,他们大量的需要来自数学理性和魔幻艺术的滋养才能创作出更好的程序艺术品。本文以python中对象方法还是通用属性函数的调用方式的选择为例阐明了代码设计艺术中小而美的精髓,欢迎品评。



内置函数是 Python 的一大特色,用极简的语法实现很多常用的操作。

它们预先定义在内置命名空间中,开箱即用,所见即所得。Python 被公认是一种新手友好型的语言,这种说法能够成立,内置函数在其中起到了极关键的作用。

举个例子,求字符串 x 的长度,Python 的写法是 len(x) ,而且这种写法对列表、元组和字典等对象也同样适用,只需要传入对应的参数即可。len() 函数是共用的。

这是一种极简哲学的体现:Simple is better than complex。

但是,有些语言并不是这样,例如在 Java 中,字符串类有一个求长度的方法,其它类也有自己的求长度的方法,它们无法共用。每次使用时,通过类或实例来调用。

同样是求字符串长度,Python 的写法:


 

saying = "Hello world!"
print(len(saying))

# 结果:12

而在 Java 中,写法可能如下(简化起见):


 

String saying = "Hello world!";
System.out.println(saying.length());

// 结果:12

Python 采用的是一种前缀表达式 ,而 Java 采用的则是后缀表达式

除了求长度,Python 的某些内置函数也能在 Java 中找到对应的表达。例如,数值型字符串 s 转化为整型数字,Python 可以用int(s)函数,而 Java 可以用 Integer.parseInt(s);整型数字转化为字符串,Python 可以用str(i),而 Java 也有String.valueOf(i)

Python 的内置函数不与特定的类绑定,它们是一级对象。而 Java 的“函数”则无法脱离类而存在,它们只是附属品。

从直观角度来看,Python 的表达似乎是更优的。但是,它们并不具有可比性 ,因为这是两套语言系统,各有独特的范畴背景,并不能轻易地化约。

就好比是,不能因为拉丁字母笔画简单,就说它优于汉字,因为在表意时,字母(表音文字)是远逊于汉字(表意文字)的。同样的,日本借用了汉字的偏旁部首而造出来的文字,虽然更省笔墨,但是也完全丧失了意蕴。

以此类比,Python 的内置函数虽有简便之美,但却丢失了某些表意功能。有些人在质疑/抨击 Python 的时候,也喜欢拿这点说事,认为这是 Python 的设计缺陷。

这就引出本文最想讨论的一个问题来:为什么 Python 要设计成 len(x) 这种前缀表达,而不是 x.len() 这样的后缀表达呢?

事实上,后缀设计也是可行的,以 Python 中列表的两个方法为例:


 

mylist = [21354]

mylist.sort()
print(mylist)   # [1, 2, 3, 4, 5]

mylist.reverse()
print(mylist)   # [5, 4, 3, 2, 1]

它们都是通过列表对象来调用,并不是凭空从内置命名空间中拿来的。语义表达得也很清楚,就是对 mylist 做排序和逆转。

恰恰那么巧,它们还有两个同父异母的兄弟 sorted() 与 reversed(),这俩是前缀表达型。


 

mylist = [21354]

sort_list = sorted(mylist)
print(sort_list)   # [1, 2, 3, 4, 5]

reverse_list = reversed(mylist)
print(list(reverse_list))   # [4, 5, 3, 1, 2]

不同的写法,都在做同一件事(不考虑它们的副作用)。因此,后缀语法并非不可行,之所以不用,那肯定是刻意的设计。

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

Python 之父 Guido van Rossum 曾经解释过这个问题(链接见文末),有两个原因:

  • 对于某些操作,前缀符比后缀更好读——前缀(和中缀)表示法在数学中有着悠久的历史,其视觉效果有助于数学家思考问题。我们可以简单地把公式 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列表,只需这篇文章就够了》这篇文章中,曾引述过 Guido 对“为什么索引从 0 开始 ”的解释。其最重要的原因,也正是 0-based 索引最优雅易懂。

让我们来先看看切片的用法。可能最常见的用法,就是“取前 n 位元素”或“从第i 位索引起,取后 n 位元素”(前一种用法,实际上是 i == 起始位的特殊用法)。如果这两种用法实现时可以不在表达式中出现难看的 +1 或 -1,那将会非常的优雅。


使用 0-based 的索引方式、半开区间切片和缺省匹配区间的话(Python最终采用这种方式),上面两种情形的切片语法就变得非常漂亮:a[:n] 和 a[i:i+n],前者是 a[0:n] 的缩略写法。

所以,我们能说 len(x) 击败 x.len() ,支撑它的是一种化繁为简、纯粹却深邃的设计思想。

面向对象的编程语言自发明时起,就想模拟我们生活于其中的现实世界。可是什么类啊、接口啊、对象啊、以及它们的方法啊,这些玩意的毒,有时候蒙蔽了我们去看见世界本质的眼睛。

桌子类有桌子类的求长度方法,椅子类有椅子类的求长度方法,无穷无尽,可现实真是如此么?求长度的方法就不能是一种独立存在的对象么?它之所以存在,是因为有“对象”存在,而不是因为有某个类才存在啊。

所以,我想说,len(x) 击败 x.len(),这还体现了 Python 对世界本质的洞察

求某个对象的长度,这种操作独立于对象之外而存在,并不是该对象内部所有的一种属性或功能。从这个角度理解,我们能够明白,为什么 Python 要设计出内置函数? 内置函数其实是对世界本质的一种捕捉。

这些见微知著的发现,足够使我们爱上这门语言了。人生苦短,我用 Python。

大好消息!为回馈MatheMagician的广大用户,本公众号正进行第二期“留言点赞送扑克”活动,详情请点击:当扑克牌遇上数学!查看活动详情,也可以直接扫描下方图片内的二维码直接购买。

640?wx_fmt=jpeg


好了,今天的数学魔术师的分享就到这里,希望各位客官能够喜欢!这里是MatheMagician,有你要的奇迹!

 

再次感谢各位客官的欣赏,MatheMagician期待您的赞赏哦~

 

更多精彩内容欢迎扫描下方二维码或点击头部公众号名MatheMagician关注我们,更欢迎把我们的精彩内容奔走相告,我们下期再见!


640?wx_fmt=jpeg

我们是谁:


MatheMagician,中文“数学魔术师”,是一个十分冷门的职业,原指用喜欢用数学原理设计魔术的魔术师或数学家。但由于数学太过艰深,变成魔术又表演困难,所以这个领域的专业研究者及其罕见。但其实,魔术设计只是数学建模的一个别致的场景;而魔术本身也蕴含着数学之外的诸如心理学,行为科学等其他广阔的议题。我们文章分享的内容涵盖统计,算法,NLP等前沿的数学及应用领域;也包括魔术思想,流程解析,鉴赏等关于魔术的思考;还有大量直接结合二者设计的数学魔术的分享。如果你对数学或者魔术感兴趣,或者喜欢思考和有内涵的文字,我们的内容一定能成为你学习成长的好伙伴!欢迎在文末或公众号留言与我交流!


往期精彩:

关于洗牌的研究(四)——洗牌混乱度计算

关于洗牌的研究(三)——洗牌过程建模

关于洗牌的研究(二)——你的扑克洗乱了吗?

关于洗牌的研究(一)——平常你都是怎么洗牌的?

你喷刘谦的样子,就是你最真实的内心

如何优雅地给扑克牌排序?(二)——排序算法的一次工程实践

刘谦的绝地反击,就像勒布朗去年单核进总决赛!

如何优雅地给扑克牌排序?(一)——排序算法的数学本质

刘谦春晚揭秘到回应——媒体正怎样影响我们这个时代?

春晚刘谦《魔壶》虽有遗憾,但这就是青春

我真的大变活人了!

如果张小龙去设计一个魔术产品,他会怎么做?

一个问题引发的统计学派之争

当代数恒等式遇上魔术(二)

当代数恒等式遇上魔术(一)

加加减减的奥秘——从数学到魔术的思考(三)

加加减减的奥秘——从数学到魔术的思考(二)

加加减减的奥秘——从数学到魔术的思考(一)

魔术和产品思维的内在联系

Reverse原理背后的数学和魔幻艺术

浅谈魔术效果的四重境界

记腾讯20周年司庆祝福魔术项目的设计经历

20周年之际送给腾讯的魔术礼物

从一段经典表演看大卫科波菲尔魔术的魅力

最大熵准则背后的一连串秘密

记一次从魔术到数学的非典型奇幻之旅


点击阅读原文,往期精彩不错过!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值