Python 2 Tutorial 第三堂(2)資料處理函式





在 Python 的 __builtin__ 模組中有一些函式,不需要 import 也可以使用,有幾個簡單好用的資料處理函式值得介紹:
  • range(start, stop[, step])
  • zip([iterable, ...])
  • enumerate(sequence, start=0)
  • reduce(function, iterable[, initializer])

range、zip 與 enumerate

要瞭解這些資料處理函式如何使用,最好的方式就是從練習開始 …

練習 6:使用 rangezipenumerate


在 Python 中,如果想使用 for in 語法來迭代 list,而且希望取得索引資訊,該如何進行呢?例如,如果有個 list = ['Justin', 'caterpillar', 'openhome'],想要有以下的顯示結果:
0, Justin
1, caterpillar
2, openhome

先給個小提示,程式基本上可以長這樣:
names = ['Justin', 'caterpillar', 'openhome']
for ______ in ______:
    print '{0}, {1}'.format(______)

試著想想,如果使用分別使用 rangezipenumerate,那麼程式中三個空白處怎麼寫呢?別忘了,查看一下 rangezipenumerate 的文件,他們都在 __builtin__ 模組的文件中。

別忘了,你可以在 Lab 檔案的 solutions 目錄找到解答。

reduce

__builtin__ 中的 reduce,有時在別的語言中會被稱為 foldLeft,它其實代表了一種高度抽象化後的流程重用,只要是打算從清單中求值的需求,基本上都可以使用它。

舉例來說,如果你想要知道 [1, 2, 3, 4, 5] 的加總,雖然可以直接撰寫迴圈來求值,不過,也可以撰寫為 reduce(lambda sum, elem: sum + elem, [1, 2, 3, 4, 5], 0) 來求值,試試在 Python 互動環境中鍵入,結果會是 15。

初學者會有點難懂 reduce 的原理,可以藉由這段動畫來理解,你也就會知道,為什麼它又在別的語言中,被稱為 foldLeft: functional-programming-for-java-developers-reduce 如果 reduce 接受的 lambda 部份,改為一個具體名稱的 add 函式,那麼就可以寫為 為 reduce(add, [1, 2, 3, 4, 5], 0) ,配合上圖,reduce 的運作就像是折紙,從 0 開始,每折一次就與藍色數字進行一次 add,折完後的結果就是加總值。

這個 reduce 函式很有用,可以有一百萬種用法,只要你想從某個清單中求值,都可以使用 reduce,只要你依需求給 reduce 要處理的函式與初值。

練習 7:使用 reduce

使用 reducefor 包含式,將以下的範例進行重構,目標是清除所有顯式的迴圈流程:
def ascending(a, b): return a - b
def descending(a, b): return -ascending(a, b)
# selection sort
def sorted(xs, compare = ascending):
    return [] if not xs else __select(xs, compare)

def __select(xs, compare):
    selected = xs[0]
    for elem in xs[1:]:
        if compare(elem, selected) < 0:
            selected = elem

    remain = []
    selected_list = []
    for elem in xs:
        if elem != selected:
            remain.append(elem)
        else:
            selected_list.append(elem)

    return xs if not remain else selected_list + __select(remain, compare)

print sorted([2, 1, 3, 6, 5])
print sorted([2, 1, 3, 6, 5], descending)

關於函數式程式設計

想要知道 reduce 的原理,可以看看 List 處理模式 中的說明。 實際上,reduce 與 for 包含式的概念源自函數式程式設計(Functional programming),嗯?好像很高深,其實如果你能完成練習 7,你已經做了一次函數式程式設計了。

不過,何時該使用函數式的元素,取決於可讀與風格問題,在 Python 中確實是有那麼一些函數式程式設計的元素,for 包含式在 Python 中應用的很多,因為可以增加可讀性,然而像 reduce 這種元素,由於可讀性並不好,因而並不太鼓勵去用它,用更具體的函式名稱來封裝 reduce 會更好,以上面的加總來說,可以寫個 sum 函式來表達意圖。實際上,在 Python 3 中,reduce 不再位於 __builtin__ 模組,而被移至 funtools 模組了。

無論如何,藉由這個練習,瞭解到 Python 可進行多重典範設計,只要你願意的話,函數式是可以的設計之一;接下來的內容,是要介紹 Python 中對永續化(Persistence)的基本支援,順便來看看幾種永續設計方式。