從新手的眼中來看 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]
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)
tuple
tuple 是一個很妙的資料結構,它和 list 的主要差別是它是唯讀的,Python 裡鮮少有這種唯讀物件。不過它較易發覺的好處是被用在 Python 的
parallel assignment 和函式傳回值。
於是在 Python 裡可以這麼寫:
a, b = b, a # swap
函式也可以一次「傳回多個結果」:
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
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