對比幾段代碼,看看你是 Python 菜鳥還是老鳥

Python 裏有個小彩蛋:

在 Python Shell 裏輸入 import this

這段話被稱作“ Python 之禪 ”( The Zen of Python ),它列舉了一些 Python 所推崇的理念,比如:

優美 勝於醜陋
明確 勝於隱晦
簡單 勝於複雜

可讀性 很重要
不要忽略 錯誤
面對不確定時, 拒絕猜測
現在做 好過不做,但盲目動手不如不做
如果你的實現很難說清楚,那是個壞想法;反之亦然

當你學完基礎,可以寫點代碼的時候,可能經常感覺自己的實現很彆扭。有經驗的程序員會一眼看出你的代碼出自一個初學者之手。這就是我們經常說的,代碼不夠 pythonic

所謂 pythonic,我覺得包含兩方面:一是代碼的風格 符合 Python 的特點 ,能合理使用 Python 的“語法糖”;二是代碼 簡潔優美,穩定性高,可讀性好,便於維護和修改 。所謂“Python 之禪”並不僅限於 Python,很多理念是編程普適的。

比如來實現對一個列表中元素的遍歷訪問,我見過很多次有人這麼寫:



for i in range(len(lst)):
    print(lst[i])

這樣的同學很可能是之前有過 C/C++ 或 Java 的經驗。這麼寫功能上沒問題,但不夠簡潔,不夠 pythonic。更好的實現方式:



for i in lst:
    print(i)

這種不影響功能,但能簡化程序、提高可讀性的語法,我們稱之爲“ 語法糖 ”( Syntactic sugar )。Python 中類似的例子還有不少,來舉幾個:

1、交換兩個變量的值,普通寫法:



temp = a
a = b
b = temp

pythonic 寫法:



a, b = b, a

2、類似的解包(unpacking)用法還可以實現多個返回值的函數。普通寫法:



def func(a, b):
    result = [b, a]
    return result
r = func(a, b)
x = r[0]
y = r[1]

pythonic 寫法:



def func(a, b):
    return b, a
x, y = func(a, b)

3、讀寫文件,普通寫法:



f = open('filename.txt')
text = f.read()
print(text)
f.close()

pythonic 寫法:



with open('filename.txt') as f:
    for line in f:
        print(line)

with 的好處是即使出錯,也會幫你關閉文件。

4、拼接字符串,普通寫法:



letters = ['h', 'e', 'l', 'l', 'o']
s = ''
for l in letters:
    s += l
print(s)

pythonic 寫法:



print(''.join(letters))

5、關於前面遍歷列表的例子,如果你想帶上索引,可以這麼寫:



for i, elem in enumerate(lst):
    print(i, elem)

遍歷字典項:



for key, value in dct.items():
    print(key, value)

6、取出列表中大於 0 的元素,生成新列表。普通寫法:



new_lst = []
for i in lst:
    if i > 0:
        new_lst.append(i)

pythonic 寫法:



new_lst = [i for i in lst if i > 0]

這個被稱爲“ 列表解析式 ”( List comprehension ,中文翻譯說法有很多),可以說是非常 pythonic 的一個用法了。

更進一步,如果數據量很大,而你對新列表僅僅是遍歷操作,並不需要一個列表對象,可以採用 生成器



new_lst = (i for i in lst if i > 0)
for i in new_lst:
    print(i)

這樣會更節省資源,提升執行效率。

7、判斷一個值是否爲True、是否爲空列表、是否是None,普通寫法:



if x == True:
    pass
if len(y) == 0:
    pass
if z == None:
    pass

pythonic 寫法:



if x:
    pass
if not y:
    pass
if z is None:
    pass

8、根據鍵名獲取字典中對應的值,普通寫法:



value = dct[key]

這樣的問題在於,如果 key 不存在,代碼就報錯跳出。於是你不得不增加更多的判斷。

pythonic 寫法:



value = dct.get(key, 0)

改用 get 方法,不存在時會得到 None,或者指定的默認值(這裏是 0)。

篇幅所限,以上僅僅是一些比較具有代表性的例子。但凡事要有度,過分追求 pythonic 的寫法也可能導致代碼的可讀性下降。比如有人喜歡把很多功能寫在一個語句中,這反倒不 pythonic 了。所以,我們需要有一些設計的原則,但又不必拘泥於具體的形式,否則就鑽入牛角尖了。

那麼對於學習者來說,如何才能寫出更 pythonic 的代碼呢?說到底還是個經驗積累的過程,菜鳥不可能看本書、上個課就一夜變成老鳥,但只要堅持得夠久就可以。我這邊給幾個建議:

  1. 多看 。看官方庫、優秀項目,學習別人的代碼。以及看一些優質的教程和經驗分享,比如 Crossin的編程教室
  2. 多搜 。當你實現一個小功能後,去網上搜一下,別人是怎麼寫的,對比下是不是比你自己的更好。舉個例子:如何從列表中刪除重複元素。你自己可以通過循環實現,但只要搜一下,就會知道 list(set(x)) 這種用法。
  3. 多寫 。自己還沒寫幾行代碼,就先別糾結什麼效率什麼風格了。最終還是要寫上足夠量的代碼,纔會有“悟道”的那一刻。

另外,對於代碼本身,Python 有一套書寫規範,叫做 PEP8 。裏面約定了很多細節,比如哪裏該空格、註釋怎麼寫、什麼地方該換行、如何命名等等。鏈接:https://www.python.org/dev/peps/pep-0008/,網上還有翻譯好的中文版,務必找時間看一看。

最後,留2個小作業:

1. 判斷 一個列表 A 是否爲另一個列表 B 的“子集” ,也就是列表 A 中的元素是否都在列表 B 中。
2. 計算 1 加到 100 的和
儘可能寫出你認爲 pythonic 的代碼。

════

其他文章及回答:

學編程:如何自學Python | 新手引導 | 一圖學Python

開發案例:智能防擋彈幕 | 紅包提醒 | 流浪地球

歡迎搜索及關注: Crossin的編程教室

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章