Python函數式編程之高階函數

函數式編程,和麪向對象編程一樣,是現在很流行的一種編程範式。

函數式編程就是一種抽象程度很高的編程範式,純粹的函數式編程語言編寫的函數沒有變量,因此,任意一個函數,只要輸入是確定的,輸出就是確定的,這種純函數我們稱之爲沒有副作用。而允許使用變量的程序設計語言,由於函數內部的變量狀態不確定,同樣的輸入,可能得到不同的輸出,因此,這種函數是有副作用的。由於Python允許變量的存在,所以Python不是純函數式編程。

函數式編程最大的特點就是將函數看作是一等公民,也就是和其他數據類型、數據結構一樣,函數也可以賦給一個變量,作爲參數、傳入其他函數,或者是作爲其他函數的返回值。而將函數作爲參數的函數我們稱之爲高階函數

高階函數

>>> f = abs
>>> f(-10)
10
>>> abs(-10)
10
>>> abs = 10
>>> abs(-10)
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    abs(-10)
TypeError: 'int' object is not callable

從上面的代碼可以看出,函數實際上是一個功能,任何一個變量可以指向一個函數,獲得這個功能;而函數名是什麼呢?函數名也是一個變量,只是這個變量初始指向了這個函數,當然也可以將這個變量指向其他值(實際上當然不能這麼寫);同時,一個變量,當然也可以作爲參數傳入函數啊,所以函數也可以作爲參數傳入其他函數

>>> def fun(x,y,p):
    print(p(x,y))
>>> fun(2,3,pow)
8

這就是一個最簡單的將函數作爲參數傳入參數的例子。在Python中有許多內置的高階函數

map

map函數接收兩個參數,一個func函數和一個Iterable對象。
func函數接收一個參數,將func函數作用於Iterable對象中的每一個元素,並返回一個map對象。

>>> def fun(x):
    return x + 3

>>> map(fun, range(10))
<map object at 0x03234BD0>
>>> m = map(fun, range(10))
>>> isinstance(m,Iterator)
True
>>> list(m)
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

從中可以看出,由於map對象也是一個Iterator,是一個懶惰序列,可以用list函數列出所有值。使用map對象可以對Iterable對象的每一個值進行函數操作,可以代替平時需要使用循環完成的功能

reduce

reduce函數接收兩個參數:func函數和一個序列。其中的func函數接收兩個參數,對序列中的值進行計算,並將結果與下一個值進行計算,直至產生最終結果

>>> from functools import reduce
>>> def add(x,y):
    return x*10+y
>>> reduce(add,range(5))
1234

**map相當於對Iterable中元素逐一操作(str也能逐字符操作),reduce則能夠將所有元素最終整合爲一個結果。**map/reduce配合使用可以實現一些強大的功能

>>> def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
    return reduce(fn, map(char2num, s))

>>> str2int('12306')
12306

filter

filter函數的作用是篩選某一序列中符合條件的序列,接收一個func函數和一個序列

>>> def is_palindrome(n):
    return str(n)==str(n)[::-1]
>>> output = filter(is_palindrome,range(1000))
>>> list(output)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99]

filter函數的重點在於構造用於判別元素是否符合條件的func函數!filter功能很強大,譬如下面的代碼實現了一個輸出素數的generator:

>>> def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n
>>> def _div_fun(n):
        def _div_check_fun(x):
            return x % n > 0
        return _div_check_fun
>>> def primes():
    yield 2
    iter = _odd_iter()
    while True:
        n = next(iter)
        yield n
        iter = filter(_div_fun(n), iter)#這裏用到了閉包
>>> p = primes()
>>> next(p)
2
>>> next(p)
3
>>> next(p)
5

生成了一個懶惰計算的generator,然後就可以一個一個生成素數了!

sorted

sorted函數是一個排序函數

>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']

sorted經常會有許多其他排序需求,這些就可以寫一個排序函數,寫入sorted函數的關鍵字參數key中

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']

>>> def fun(s):
    return s[1].lower()
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=fun, reverse=True)
['Credit', 'bob', 'Zoo', 'about']

上面的例子,想要通過元素的第二個字母對list進行排序,那麼傳入的key參數函數中就應該返回第二個字母。

從上面的例子可以看出,高階函數的抽象能力非常強大,能夠使得代碼保持簡潔!

(By MrHammer 2016-05-21 下午5點 @Hohai Rainy)

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