len(x) 擊敗 x.len(),從內置函數看 Python 的設計思想

来源:https://www.cnblogs.com/pythonista/archive/2019/04/21/10746798.html
-Advertisement-
Play Games

內置函數是 Python 的一大特色,用極簡的語法實現很多常用的操作。 它們預先定義在內置命名空間中,開箱即用,所見即所得。Python 被公認是一種新手友好型的語言,這種說法能夠成立,內置函數在其中起到了極關鍵的作用。 舉個例子,求字元串 x 的長度,Python 的寫法是 len(x) ,而且這 ...


 

內置函數是 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() 函數的首碼表達方式是最好的體現。我想起在《超強彙總:學習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 的由來:http://suo.im/4ImAEo

Guido 解釋 0 索引的由來:http://suo.im/5cr12S

本文原創並首發於公眾號【Python貓】,未經授權,請勿轉載。

原文地址:https://mp.weixin.qq.com/s/pKQT5wvyaSNFvnJexiCC8w

公眾號【Python貓】, 本號連載優質的系列文章,有喵星哲學貓系列、Python進階系列、好書推薦系列、技術寫作、優質英文推薦與翻譯等等,歡迎關註哦。後臺回覆“愛學習”,免費獲得一份學習大禮包。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • C語言的課後習題 求數列:2/1,3/2,5/3,8/5,13/8,21/13,...前50項的和 數列規律: 第二項的分母是【前一項分子】 第二項的分子是【前一項分子與分母的和】 ...
  • numpy 與 matplotlib 的應用 一、庫函數介紹 1. numpy庫 NumPy(Numeric Python)提供了一個N維的數組類型ndarray,Numpy底層使用C語言編寫,內部解除了GIL(全局解釋器鎖),其對數組的操作速度不受Python解釋器的限制,效率遠高於純Python ...
  • @[toc] 實戰內容 海倫女士一直使用線上約會網站尋找適合自己的約會對象。儘管約會網站會推薦不同的人選,但她並不是喜歡每一個人。經過一番總結,她發現自己交往過的人可以進行如下分類: 不喜歡的人 魅力一般的人 極具魅力的人 海倫收集約會數據已經有了一段時間,她把這些數據存放在文本文件datingTe ...
  • ArrayBlockingQueue的實現方式? ArrayBlockingQueue是否需要擴容? ArrayBlockingQueue有什麼缺點? ...
  • 如果你發現所有的功能都報找不到映射的錯,有可能是因為mapper文件沒有被編譯 在eclipse中,把資源文件放在src下,是可以被編譯的 但是在idea中,直接把資源文件放在src下,如果不進行設置,是不會被編譯的,idea對src下的xml等資源文件是預設不編譯的 ​ 在pom.xml中加入以下 ...
  • 1. 游戲功能和流程圖 實現功能:翻開兩個一樣的牌子就顯示,全部翻開游戲結束,設置5種圖形,7種顏色,游戲開始提示隨機8個牌子 游戲流程圖 2. 游戲配置 配置游戲目錄 配置游戲(game_conf.py) 配置顏色(color.py) 配置形狀(shape.py) 3. 游戲使用工具函數(view ...
  • 1.當前路徑及路徑下的文件 os.getcwd():查看當前所在路徑。 os.listdir(path):列舉目錄下的所有文件。返回的是列表類型。 2.os.path.splitext(path) 分離文件名與擴展名;預設返回(fname,fextension)元組,可做分片操作 >>> os.pa ...
  • 如 "abcdt" 反轉之後是 "tdcba" 思路1: 運用遞歸的方法進行反轉 假設反轉方法為 reverseString(String str)1)當字元串為空或者只有一個字元時,返回原字元2)當字元串有兩個以上(長度為len)的字元時,反轉後的字元串為 第二個字元開始的子串的反轉結果+第一個字 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...