函數是Python內建支持的一種封裝,咱們經過把大段代碼拆成函數,經過一層一層的函數調用,就能夠把複雜任務分解成簡單的任務,這種分解能夠稱之爲面向過程的程序設計。函數就是面向過程的程序設計的基本單元。html
而函數式編程(請注意多了一個「式」字)——Functional Programming,雖然也能夠歸結到面向過程的程序設計,但其思想更接近數學計算。python
咱們首先要搞明白計算機(Computer)和計算(Compute)的概念。編程
在計算機的層次上,CPU執行的是加減乘除的指令代碼,以及各類條件判斷和跳轉指令,因此,彙編語言是最貼近計算機的語言。api
而計算則指數學意義上的計算,越是抽象的計算,離計算機硬件越遠。app
對應到編程語言,就是越低級的語言,越貼近計算機,抽象程度低,執行效率高,好比C語言;越高級的語言,越貼近計算,抽象程度高,執行效率低,好比Lisp語言。編程語言
函數式編程就是一種抽象程度很高的編程範式,純粹的函數式編程語言編寫的函數沒有變量,所以,任意一個函數,只要輸入是肯定的,輸出就是肯定的,這種純函數咱們稱之爲沒有反作用。而容許使用變量的程序設計語言,因爲函數內部的變量狀態不肯定,一樣的輸入,可能獲得不一樣的輸出,所以,這種函數是有反作用的。函數式編程
函數式編程的一個特色就是,容許把函數自己做爲參數傳入另外一個函數,還容許返回一個函數!函數
Python對函數式編程提供部分支持。因爲Python容許使用變量,所以,Python不是純函數式編程語言。測試
高階函數英文叫Higher-order function。什麼是高階函數?咱們以實際代碼爲例子,一步一步深刻概念。ui
以Python內置的求絕對值的函數abs()
爲例,調用該函數用如下代碼:
#coding=utf-8 print abs(-10)
可是,若是隻寫abs
呢?
>>> abs <built-in function abs>
可見,abs(-10)
是函數調用,而abs
是函數自己。
要得到函數調用結果,咱們能夠把結果賦值給變量:
>>> x = abs(-10) >>> x 10
可是,若是把函數自己賦值給變量呢?
>>> f = abs >>> f <built-in function abs>
結論:函數自己也能夠賦值給變量,即:變量能夠指向函數。
若是一個變量指向了一個函數,那麼,能否經過該變量來調用這個函數?用代碼驗證一下:
那麼函數名是什麼呢?函數名其實就是指向函數的變量!對於abs()
這個函數,徹底能夠把函數名abs
當作變量,它指向一個能夠計算絕對值的函數!
若是把abs
指向其餘對象,會有什麼狀況發生
>>> abs = 10 >>> abs(-10) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not callable
把abs
指向10
後,就沒法經過abs(-10)
調用該函數了!由於abs
這個變量已經不指向求絕對值函數而是指向一個整數10
!
固然實際代碼絕對不能這麼寫,這裏是爲了說明函數名也是變量。要恢復abs
函數,請重啓Python交互環境。
注:因爲abs
函數其實是定義在import builtins
模塊中的,因此要讓修改abs
變量的指向在其它模塊也生效,要用import builtins; builtins.abs = 10
。
既然變量能夠指向函數,函數的參數能接收變量,那麼一個函數就能夠接收另外一個函數做爲參數,這種函數就稱之爲高階函數。
一個最簡單的高階函數:
當咱們調用add(-5, 6, abs)
時,參數x
,y
和f
分別接收-5
,6
和abs
,根據函數定義,咱們能夠推導計算過程爲:
#coding=utf-8 def add(x, y, f): return f(x) + f(y) print add(-5,6,abs)
編寫高階函數,就是讓函數的參數可以接收別的函數。
Python內建了map()
和reduce()
函數。
若是你讀過Google的那篇大名鼎鼎的論文「MapReduce: Simplified Data Processing on Large Clusters」,你就能大概明白map/reduce的概念。
咱們先看map。map()
函數接收兩個參數,一個是函數,一個是Iterable
,map
將傳入的函數依次做用到序列的每一個元素,並把結果做爲新的Iterator
返回。
舉例說明,好比咱們有一個函數f(x)=x2,要把這個函數做用在一個list [1, 2, 3, 4, 5, 6, 7, 8, 9]
上,就能夠用map()
實現以下:
\
如今,咱們用Python代碼實現:
#coding=utf-8 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]
map()
傳入的第一個參數是f
,即函數對象自己。因爲結果r
是一個Iterator
,Iterator
是惰性序列,所以經過list()
函數讓它把整個序列都計算出來並返回一個list。
你可能會想,不須要map()
函數,寫一個循環,也能夠計算出結果:
#coding=utf-8 L = [] def f(x): return x * x for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]: L.append(f(n)) print(L)
的確能夠,可是,從上面的循環代碼,能一眼看明白「把f(x)做用在list的每個元素並把結果生成一個新的list」嗎?
因此,map()
做爲高階函數,事實上它把運算規則抽象了,所以,咱們不但能夠計算簡單的f(x)=x2,還能夠計算任意複雜的函數,好比,把這個list全部數字轉爲字符串:
的確能夠,可是,從上面的循環代碼,能一眼看明白「把f(x)做用在list的每個元素並把結果生成一個新的list」嗎?
因此,map()
做爲高階函數,事實上它把運算規則抽象了,所以,咱們不但能夠計算簡單的f(x)=x2,還能夠計算任意複雜的函數,好比,把這個list全部數字轉爲字符串:
#coding=utf-8 print list(map(str,[1,2,3,4,5,6,7,8,9]))
只須要一行代碼。
再看reduce
的用法。reduce
把一個函數做用在一個序列[x1, x2, x3, ...]
上,這個函數必須接收兩個參數,reduce
把結果繼續和序列的下一個元素作累積計算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
比方說對一個序列求和,就能夠用reduce
實現:
#coding=utf-8 from functools import reduce def f(x): return x * x def add(x,y): return x + y print reduce(add,[1,3,5,7,9])
25
固然求和運算能夠直接用Python內建函數sum()
,不必動用reduce
。
可是若是要把序列[1, 3, 5, 7, 9]
變換成整數13579
,reduce
就能夠派上用場:
from functools import reduce def f(x): return x * x def add(x,y): return x + y def fn(x,y): return x * 10 + y print reduce(fn,[1,3,5,7,9])
13579
這個例子自己沒多大用處,可是,若是考慮到字符串str
也是一個序列,對上面的例子稍加改動,配合map()
,咱們就能夠寫出把str
轉換爲int
的函數:
>>> from functools import reduce >>> 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] ... >>> reduce(fn, map(char2num, '13579')) 13579
整理成一個str2int
的函數就是
from functools import 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))
還能夠用lambda函數進一步簡化成:
from functools import reduce 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] def str2int(s): return reduce(lambda x, y: x * 10 + y, map(char2num, s))
還能夠用lambda函數進一步簡化成:後面再細研究,在此不作演示,實際上是不知道呀
1.利用map()
函數,把用戶輸入的不規範的英文名字,變爲首字母大寫,其餘小寫的規範名字。輸入:['adam', 'LISA', 'barT']
,輸出:['Adam', 'Lisa', 'Bart']
:
#coding=utf-8 from functools import reduce def normalize(name): return name.capitalize() L1 = ['adam', 'LISA', 'barT'] L2 = list(map(normalize,L1)) print 'L2', L2
小總結:經測試 capitalize()是字符串方法,可將字符串首字母大寫,其他字母小寫化!,map2個參數,函數,隊列,調用的函數的參數將是隊列中的每個值,單獨分開來去掉用函數
2.Python提供的sum()
函數能夠接受一個list並求和,請編寫一個prod()
函數,能夠接受一個list並利用reduce()
求積:
#coding=utf-8 from functools import reduce def prod(x,y): return x * y L = [3, 5, 7, 9] print reduce(prod,L)
總結,reduce有2個參數,(調用的函數,序列),被調用的函數應有2個參數--例子是整個的序列,不懂耶,之後再說--,2個參數分別對應着序列的順序排列變量