內置函數是 Python 的一大特點,用極簡的語法實現不少經常使用的操做。java
它們預先定義在內置命名空間中,開箱即用,所見即所得。Python 被公認是一種新手友好型的語言,這種說法可以成立,內置函數在其中起到了極關鍵的做用。python
舉個例子,求字符串 x 的長度,Python 的寫法是 len(x) ,並且這種寫法對列表、元組和字典等對象也一樣適用,只須要傳入對應的參數便可。len() 函數是共用的。編程
這是一種極簡哲學的體現:Simple is better than complex。app
可是,有些語言並非這樣,例如在 Java 中,字符串類有一個求長度的方法,其它類也有本身的求長度的方法,它們沒法共用。每次使用時,經過類或實例來調用。編程語言
一樣是求字符串長度,Python 的寫法:函數
saying = "Hello world!"
print(len(saying))
# 結果:12
複製代碼
而在 Java 中,寫法可能以下(簡化起見):學習
String saying = "Hello world!";
System.out.println(saying.length());
// 結果:12
複製代碼
Python 採用的是一種前綴表達式 ,而 Java 採用的則是後綴表達式 。ui
除了求長度,Python 的某些內置函數也能在 Java 中找到對應的表達。例如,數值型字符串 s 轉化爲整型數字,Python 能夠用 int(s)
函數,而 Java 能夠用 Integer.parseInt(s)
;整型數字轉化爲字符串,Python 能夠用 str(i)
,而 Java 也有 String.valueOf(i)
。spa
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)
重寫成 x*a + x*b
,但一樣的事,以原生的面向對象的方式實現,就比較笨拙。解釋完這兩個緣由以後,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。
關聯閱讀:
Guido 解釋 len 的由來:suo.im/4ImAEo
Guido 解釋 0 索引的由來:suo.im/5cr12S
本文原創並首發於公衆號【Python貓】,未經受權,請勿轉載。
原文地址:mp.weixin.qq.com/s/pKQT5wvya…
公衆號【Python貓】, 本號連載優質的系列文章,有喵星哲學貓系列、Python進階系列、好書推薦系列、技術寫做、優質英文推薦與翻譯等等,歡迎關注哦。後臺回覆「愛學習」,免費得到一份學習大禮包。