python函數式編程之高階函數學習


基本概念

函數式編程,是一種抽象程度很高的編程範式,純粹的函數式編程語言編寫的函數沒有變量。因此,任意一個函數,只要輸入確定,輸出就確定的這種函數我們稱之爲純函數,我們稱這種函數沒有副作用。而允許使用白變量的程序設計語言,由於函數內部的變量狀態是不確定的,同樣的輸入可能有不同的輸出,我們稱這種函數爲有副作用的。
函數式編程的一個特點就是,允許把函數本身作爲參數傳遞給另一個函數,還允許返回一個函數!
Python對函數式編程提供部分支持。由於Python允許使用變量,因此,Python不是純函數式編程語言。
(這部分內容摘抄與廖雪峯老師的博客文章,自己也進行了學習)

高階函數

  • 變量可以指向函數

    #變量可以指向函數
    f = abs;
    print(abs(-10));#10
    print(f(-10));#10
    #在這裏用f和abs調用的結果和效果是一樣的
    

    說明變量f 已經指向了函數 abs本身。

  • 函數名也是變量
    函數名就是指向函數的變量。如:

    abs = 10;
    print(abs(-10));
    # Traceback (most recent call last):
    #   File "test01.py", line 164, in <module>
    #     print(abs(-10));
    # TypeError: 'int' object is not callable
    

    abs已經被賦值10,是一個指向10的變量了,就不能通過abs(-10)來調用該函數了,因爲abs這個變量已經不指向求絕對值函數了。

  • 傳入函數
    就是一個函數可以作爲另一個函數的參數,這種函數稱爲高階函數。

    #一個簡單的高階函數
    def add(x, y, f):
        return f(x) + f(y);
    print(add(5, -6, abs));#11
    
map/reduce

python內建了map()和reduce()函數。

  • map()函數
    map函數接收兩個參數,一個是函數,一個是iterable(可迭代的對象),map將傳入的函數一次作用到序列的每個元素,並把結果作爲新的iterator返回。

    #map()函數
    def f(x):
        return x * x;
    r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
    print(list(r));
    # [1, 4, 9, 16, 25, 36, 49, 64, 81]
    
  • reduce()函數
    該函數必須接收兩個參數,reduce把函數結果繼續和序列的下一個元素做累積計算。
    如:累加

    #reduce()函數
    from functools import reduce;
    def add1(x, y):
        return x + y;
    print(reduce(add1, [1, 3, 5, 7, 9]));#25
    

    這並不是reduce的用武之地,當我們要把上面的數列變成整數13579時,reduce就排上用場了:

    def fn(x, y):
        return x * 10 + y;
    print(reduce(fn, [1, 3, 5, 7, 9]));
    

    這個例子也沒什麼意義,但是當我們要把字符串 str 轉換成int的函數時,就用上了reduce(結合map)。

filter()函數
  • filter
    python內置的filter函數用於過濾序列。和map類似也接收一個函數和一個序列,但是不同的是,filter把傳入的函數依次作用於每個元素,然後根據返回值是true還是false決定保留還是丟棄該元素。
    在一個list中,刪掉偶數,只保留奇數:

    #filter函數
    #在一個list中刪除偶數,只保留奇數
    def is_odd(n):
        return n % 2 == 1;
    print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])));
    # 1, 5, 9, 15
    
  • 用filter求素數
    思想:計算素數的一個方法是埃氏篩法,它的算法理解起來非常簡單:

    1. 首先,列出從2開始的所有自然數,構造一個序列:

      2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

    2. 取序列的第一個數2,它一定是素數,然後用2把序列的2的倍數篩掉:

      3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

    3. 取新序列的第一個數3,它一定是素數,然後用3把序列的3的倍數篩掉:

      5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

    4. 取新序列的第一個數5,然後用5把序列的5的倍數篩掉:

      7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

不斷篩下去,就可以得到所有的素數。
註明:該算法描述來源於廖雪峯老師的文章。

sorted()函數

排序算法

#sorted函數排序
print(sorted([36, -2, 5, 7, 1, -10]));
# [-10, -2, 1, 5, 7, 36];

sorted也是一個高階函數,可以接受一個key函數來實現自定義的排序,列如按絕對值大小排序:

#sorted函數排序
print(sorted([36, -2, 5, 7, 1, -10], key=abs));
# [1, -2, 5, 7, -10, 36]

sorted函數可以用來對字符串進行排序。
sorted()也是一個高階函數。用sorted()排序的關鍵在於實現一個映射函數。

總結

對函數式編程的學習這部分比較重要,學習這部分讓我想到了前端框架reactJs,react也是強調函數式編程的,也是react的特性。就是說一個函數可可以作爲另一個函數的參數。上面的學習例子都是很簡單的,需要自己不斷的練習。

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