乐趣区

关于python:lenx-击败-xlen从内置函数看-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 = [2, 1, 3, 5, 4]

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

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

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

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

mylist = [2, 1, 3, 5, 4]

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) 重写成 xa + 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() 函数的前缀表达方式是最好的体现。

  • 让咱们来先看看切片的用法。可能最常见的用法,就是“取前 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。

以上就是本次分享的所有内容,想要理解更多 python 常识欢送返回公众号:Python 编程学习圈 ,发送“J”即可收费获取,每日干货分享

退出移动版