從新手的眼中來看 Python,比較能看出 Python 和其它語言不同之處。最近有機會幫別人快速上手 Python,就順便整理一下我從中發覺 Python 較為突出的優點。
list、dictionary and string
平時 coding 最常用到的 container 就是 list 和 dictionary,另外也會常用到字串操作,Python 提供方便的方法來操作它們。string 可看成一個有實作 list 介面的類別,一些常用操作像是 slice:"abcd"[1:3] 回傳 "bc";負數的索引: "abcd"[-1] 回傳 "d";直接和 for-loop 整合在一起:
In [1]: for ch in "abcd": ....: print ch ....: a b c d
讓存取這些常用資料型態輕鬆許多。
iterator
使用 iterator 比傳統的 for (i=0; i 來得清楚,Python 針對 iterator 下了不少工夫,提供好用的輔助函式,像是 enumerate 補足需要用到 index 的情況:
In [2]: for i, n in enumerate([1, 3, 5]): ....: print i, n ....: 0 1 1 3 2 5
使用 zip 整合多個 list:
In [3]: names = ["John", "Marry", "Tom"] In [4]: sexes = ["Male", "Female", "Male"] In [5]: for name, sex in zip(names, sexes): ....: print name, sex ....: John Male Marry Female Tom Male
map, filter and reduce
任何使用過 map 的人,都會喜歡 map 輕巧的用法,來看幾個例子:
In [1]: map(int, ["12", "37", "999"]) Out[1]: [12, 37, 999] In [2]: map(str, [12, 37, 999]) Out[2]: ['12', '37', '999']
int 是一個函式,將傳入的物件轉成整數;str 則是轉成字串。使用 map 可以將一個 iterator 轉為另一種 list。
另一個常見的情境是,從一個 list 裡篩選出需要的物件,比方說只留下偶數:
In [1]: numbers = [1, 2, 3, 4, 5] In [2]: filter(lambda x: x % 2 == 0, numbers) Out[2]: [2, 4]
或像 filter(lambda s: s.endswith('.py'), file_names) 只留下結尾為 ".py" 的字串。
除 map 和 filter 的重心放在轉換 list 之外,reduce 則是將 list 匯整成一個物件。有了這些函式,就能任意的操作 list,用以匯整或擴散資料容器。
比方說將一串數字加起來:
In [1]: numbers = [1, 2, 3, 4, 5] In [2]: reduce(lambda x, y: x + y, numbers, 0) Out[2]: 15
上面這個例子可以用內建的 sum 取代,來看另一個複雜點的例子,將一串 0、1 值合成一個整數:
In [1]: bits = [0, 1, 0, 0, 1] # bits[i] 的值表示 2^i 的系數 In [2]: reduce(lambda x, (i, b): x | (b << i), enumerate(bits), 0) Out[2]: 18
list comprehension
map 和 filter 雖然方便,要用到 lambda 或是混合使用時就沒那麼好讀了。Python 提供一個重量級的武器 list comprehension 來解決這問題。比方說留下偶數並乘以三再加一:
In [1]: numbers = [1, 2, 3, 4, 5] In [2]: [n * 3 + 1 for n in numbers if n % 2 == 0] Out[2]: [7, 13]
綜合以上的語法,可以輕鬆地寫出易懂的 quick sort:
def qsort(numbers): if len(numbers) <= 1: return numbers pivot = numbers[0] rest = numbers[1:] smaller = [n for n in rest if n <= pivot] larger = [n for n in rest if n > pivot] return qsort(smaller) + [pivot] + qsort(larger)
對於習慣 C、C++、Java 世界的人來說,應該不曾看過這麼直覺易懂的quick sort 吧。
tuple
tuple 是一個很妙的資料結構,它和 list 的主要差別是它是唯讀的,Python 裡鮮少有這種唯讀物件。不過它較易發覺的好處是被用在 Python 的parallel assignment 和函式傳回值。
於是在 Python 裡可以這麼寫:
a, b = b, a # swap
Python 在看到 b, a 時會產生一個 tuple 表示 (b, a),再透過 tuple 達到parallel assignment。
函式也可以一次「傳回多個結果」:
In [1]: def divide_and_mode(a, b): ...: if b == 0: ...: return None, None ...: return a / b, a % b ...: In [2]: divide_and_mode(7, 3) Out[2]: (2, 1) In [3]: a, b = divide_and_mode(7, 3) In [4]: a Out[4]: 2 In [5]: b Out[5]: 1
原理一樣是先轉成 tuple 再傳回,再視等號左側放什麼,決定要存成 tuple 或做 parallel assignment。
2012-01-25 更新
應該沒什麼力氣更新續篇,在這裡簡短描述一下,有興趣的人可以找看看相關介紹。
with
在 Python 2.6 後,支援用 with 管理資源。像讀檔案可以用 with 的方式寫:
# 印出所有使用者的 id with open('/etc/passwd') as fr: for line in fr: print line.split(':')[0]
在進入 with 的 block 前,會呼叫 file object 的 __enter__ 以獲得 file descriptor;在離開 block 前會呼叫 __exit__ 關掉 file descriptor。即使中間呼叫了 sys.exit() 或丟出 exception,仍會執行到 __exit__,不用擔心會漏關。方便用在許多情境 (比方說 lock / unlock、自動 flush output buffer),易讀易用。
內建常用函式庫
簡單不易出錯的語法
舉幾個寫 C 可能發生的問題,但在 Python 的語法下則不會發生:
if (condition); { // BUG!! 這裡的程式一定會被執行 }
if (x < 60) number_of_fail++; total_fail_score += x; // BUG!! 這行每次都會執行
另外,由於 Python 的 condition 只能是 expression,不能是 assignment。不會有 if (x -= 3 < 0) 這種 bug。
Reference:
http://fcamel-fc.blogspot.ca/2011/08/python-1.html
No comments:
Post a Comment