天天看點

python函數式程式設計FP---學習筆記函數式程式設計FP

主要是跟着廖老師的學習教材學習

函數式程式設計FP

函數是把一段能夠實作某種特定功能的代碼取了一個名字,在這之後調用這個名字即可實作功能的一種封裝。把一個複雜任務通過層層函數調用簡單化。

函數式程式設計——Functional Programming能夠調用多個函數來實作功能。

函數式程式設計是一種抽象程度很高的程式設計範式,純粹的函數式程式設計語言編寫的函數沒有變量,而python允許使用變量,是以python不是純函數式程式設計語言。

python函數式程式設計FP---學習筆記函數式程式設計FP

高階函數

函數名也是變量,若把一些内置函數定義成數值,那麼就會喪失原有功能。

>>> str = 10
>>> str(-10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
           

可以使用del str來恢複pow函數。當然最好還是重新開機python互動環境。

函數式程式設計的參數可以為函數`

def add(x, y, f):
    return f(x) + f(y)

print(add(-5, 6, str))
-56
           

map/reduce

map

map() 函數文法:

map(function, iterable)

map作用在于把iterable内的每個元素都調用一次function,傳回每次function傳回值組成的iterator.

map接收兩個參數,一個是函數,另一個是可疊代對象(比如list,tuple),map結果傳回一個iterator(惰性序列),是以我們可以通過list()函數來把整個序列計算出來傳回一個list,也可以巧妙運用list的append方法生成一個新的list.

reduce

reduce() 函數文法:

reduce(function, iterable[, initializer])

initializer為可選參數。

有别于map的是

1.reduce中的function必須接受兩個參數,把結果當做新參數再與序列下一個元素放入function進行計算。最簡單的例子就是sum除了内建函數還可以這樣實作

from functools import reduce
def add(x,y):
    return x+y
print(reduce(add,range(0,10)))
           

通過匿名函數lambda,代碼還能進一步簡化

from functools import reduce
print(reduce(lambda x,y:x+y,range(0,10)))
           

filter

filter()也就是過濾函數,與map一樣也接受一個函數和序列,也傳回一個Iterator

案例:篩選1到200的回數(從左往右和從右往左都是一樣的數)

def huishu(n))
	return n==int(str(n)[::-1])
           

sorted

sorted()是排序函數,可以接受一個key函數來自定義排序,key作用于每一個字元。

案例:對一組表示學生名字和成績的tuple按照名字排序以及按成績排序。

L = [('Bob', 75), ('Adam', 92), ('Bart', 66)]
def by_name(t):
	return t[0]
def by_grade(h):
	return h[-1]
L2 = sorted(L, key=by_name)
L3 = sorted(L, key=by_grade)
           

傳回函數

高階函數可以把函數作為傳回值。

比如定義一個求和函數:

>>> def calc_sum(num_list):
    s = 0
    for i in num_list:
        s += i
    return s
           

倘若我們不需要立即求和,而是放在後面代碼中根據需要再計算(ps:在我看來相對于一個小括号包裹了該函數),我們可以傳回求和的函數而非計算結果。

>>> def lazy_calc_sum(num_list):
    def calc_sum():
        s = 0
        for i in num_list:
            s += i
        return s
    return calc_sum

>>> f_lazy = lazy_calc_sum([1,2,3,4])
>>> f_lazy
<function lazy_calc_sum.<locals>.calc_sum at 0x0000003B8D25A2D8>
>>> f_lazy()
10
           

在這之中調用lazy_calc_sum()傳回的是calc_sum(),唯有調動f_lazy時才是真正計算結果。

注:哪怕執行個體調用同一個函數,且參數一樣,它的傳回函數都是一個新的函數。也就是

>>> f1 = lazy_calc_sum([1, 3, 5, 7, 9])
>>> f2 = lazy_calc_sum([1, 3, 5, 7, 9])
>>> f1==f2
False
>>>print(id(f1))
140496661629400
>>>print(id(f2))
140496433033288
           

閉包

關于閉包的知識參考了一位部落客的文章

連結:原文

如果一個函數定義中引用了函數外定義的變量,并且該函數可以在其定義環境外被執行。這樣的一個函數我們稱之為閉包。

示例:

def outer():
    a = 6
    def inner():
        b = 8
        print(a)
        print(b)
    return inner

if __name__ == '__main__':
    res = outer()
    res()

執行結果:

>>>6
>>>8
           

自由變量a作為outer()的局部變量被内部函數引用。而當a在内部函數以局部變量定義時,就不存在閉包了

def outer():
    a = 6
    def inner():
        b = 8
        a += 1
        print(a)
        print(b)
    return inner

if __name__ == '__main__':
    res = outer()
    res()

執行函數會報錯:UnboundLocalError: local variable 'a' referenced before assignment
           

局部變量在某種程度上優先級是大于全局變量的。

匿名函數

  1. Python用lambda文法定義匿名函數
  2. lambda隻需用表達式而無需申明
  3. lambda沒有函數名
  4. 在定義時直接被調用,冒号後面的表達式有且隻能有一個
  5. 自帶return

裝飾器

本質上,decorator是一個傳回函數的高階函數。在代碼運作期間增加其功能,不會修改該函數定義。

定義裝飾器的時候用def,調用的時候須用@.python内置的functools.wraps裝飾器可以把原始函數的__name__等屬性複制到wrapper()函數中。

案例:設計dectorator,列印該函數執行時間。

import time
import functools


def metric(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        start = time.time()
        func(*args, **kw)  # 需要先運作一下函數,記錄開始時間和結束時間。
        end = time.time()
        print('%s executed in %s ms' % (func.__name__, (end - start)))
        return func(*args, **kw)

    return wrapper


@metric
def fast(x, y):
    time.sleep(0.0012)
    return x + y;


@metric
def slow(x, y, z):
    time.sleep(0.1234)
    return x * y * z;


f = fast(11, 22)
s = slow(11, 22, 33)
if f != 33:
    print('測試失敗!')
elif s != 7986:
    print('測試失敗!')
           

偏函數

此偏函數不等同于數學上的偏函數,用于把一個函數的某些參數設定預設值,傳回一個新的函數。

案例:

import functools
sorted2 = functools.partial(sorted,key=abs)
print(sorted2([1,-3,-4]))