本篇文章起源於StackOverflow上一個熱度非常高的問題:
@Ray Vega (提問者)
舉例說明,現在我得到了如下代碼:
a = []
我如何該檢查
a
是否為空?
面對這個問題,各路高手給出了不盡相同的回答。
最高票答案十分簡潔:
@Patrick (答題者)
if not a: print("List is empty")
利用空列表的隱式布爾值是一個非常Pythonic的方式。
排名第二的答案與第一觀點相同,並以PEP 8作為依據,說明不僅是列表,Python中的內置序列類型都有推薦的做法:
@Harley Holcombe (答題者)
PEP 8 風格指南 給出了推薦的Pythonic的方法(其中Yes 表示推薦, No表示不推薦):
對序列數據類型(字符串,列表,元組),利用空列表隱式為
False
的事實Yes: if not seq: if seq: No: if len(seq): if not len(seq):
然而,排名第三的答案給出了不同的看法:
我更推薦顯式的方法:
if len(li) == 0: print('the list is empty')
這種方式明確聲明了
li
是一個序列類型的變量,並且我們是在檢查它的長度。而if not li
的問題在於,它會給我li
是一個布爾類型變量的印象。
那么,判斷列表(序列)是否為空的正確姿勢到底是什么呢?這貌似只是一個編碼風格的問題,但我們分別從兩類不同看法的出發點挖掘更深層次的原因,可以讓自己更明確地選擇適合自己的風格。
什么是PEP 8
PEP,全稱Python Enhancement Proposals (翻譯過來就是Python增強建議書),有興趣的讀者可以直接閱覽PEP原文。 PEP本質上是一份Python的官方文檔庫,給Python社區提供信息,或者描述Python的新特性或開發進展。而PEP 8是這個文檔庫中的一員,專門用於描述Python的編碼規范,這里規范是指官方推薦的,被認為是更符合Python設計哲學的各種實踐。
同樣實現相同的功能,不同編程語言的傾向於使用不同的風格,這是因為每種語言都有自身的設計目的,而Python的設計目的非常明顯:優雅,簡單,可讀。正如PEP 20(另一份PEP)Python之禪中所說:
簡單優於復雜
於是,依據序列長度是否為0將序其隱式轉化為布爾值,成為Python實現中的特性之一,並成為官方推薦的判斷序列是否為空的Pythonic方式。
關於Python是如何做到序列類型乃至所有類型到布爾值的隱式轉化的,我會專門就此問題寫文討論,歡迎關注。
什么是動態類型
那么為什么還會有人提出明確使用看上去復雜的if len(li) == 0
來判斷,並且還有很多人表示贊同呢?這其實來源於Python語言的動態類型特性。
關於什么是動態類型,我也會另外專門討論,在這里,我們只需闡明,動態類型帶來了一個弊端,我們無法對變量在程序中某一位置的類型進行准確判斷。在閱讀Python代碼的過程中,我們可能最為頭痛的問題就是:這里這個變量是什么(類型)???唯一留給我們的線索也許只有變量名了。而在靜態類型語言,如Java中,一個變量的類型從其聲明時是確定的,在程序中不會發生改變。
回到我們的問題,if not li
,看到這段代碼的程序猿可能會疑惑,這里的li
變量是什么,是一個布爾類型?還是一個整型?這里的測試是在干什么?而if len(li) == 0
可以很大程度上進行提示:這大抵是個容器性質的變量,我們在做的大抵是判斷其元素數量是否為0.
總結
討論到這里,我們仍然只能說,Python中如何判斷一個列表是否為空,是一個與風格和習慣有關的問題,但是深入探究我們發現,風格和習慣不是目的,而是手段,代碼最終是服務於編碼者和閱讀者的,拋開性能問題,只從可讀性出發,你希望閱讀這份代碼的人接受到的是什么,是簡單優雅,還是信息提示,這才是比所謂Pythonic更值得思考的問題。
獲取最新文章更新,歡迎關注我的公眾號: StackOverflow Daily