高階python 函數(shù)式編程
- 函數(shù)式
函數(shù)式編程(FunctionalProgramming)
- 基于lambda演示得一種編程方式
? ? - 程序中只有函數(shù)
? ? - 函數(shù)可以做為參數(shù)外莲,作為返回值,
? ? - 純函數(shù)式編程語(yǔ)言 : LISP,Haskell
- python函數(shù)式編程只是借鑒函數(shù)式編程得一些特點(diǎn)兔朦,可以理解成一半函數(shù)式一半python
- 需要講述
? ? - 高階函數(shù) :把函數(shù)作為參數(shù)使用得函數(shù)偷线,叫高階函數(shù);
? ? - 返回函數(shù) :把函數(shù)做為返回值得函數(shù)沽甥,叫返回函數(shù)声邦;
? ? - 裝飾器 :就是用于拓展原來(lái)函數(shù)功能的一種函數(shù),這個(gè)函數(shù)的特殊之處在于它的返回值也是一個(gè)函數(shù)摆舟,使用python裝飾器的好處就是在不用更改原函數(shù)的代碼前提下給函數(shù)增加新的功能亥曹;
? ? - 偏函數(shù) :
### lambda 表達(dá)式
- 函數(shù):最大程度復(fù)用代碼
- lambda表達(dá)式(匿名函數(shù))
? ? - 一個(gè)表達(dá)式邓了,沒(méi)有方式名稱
```python
# 定義一個(gè)返回函數(shù),返回fun2媳瞪。通過(guò)變量fun進(jìn)行接收返回值骗炉,打印返回值類型,并調(diào)用返回函數(shù)材失。
def fun(a):
? ? def fun2():
? ? ? ? print "this is fun2"
? ? print a
? ? return fun2
fun = fun(2)
print (type(fun))
print fun()
```
系統(tǒng)高階函數(shù) - map
- 原意就是映射痕鳍,即把集合或列表得元素硫豆,每一個(gè)元素都按照一定規(guī)則進(jìn)行操作龙巨,生成一個(gè)新的列表或者集合
- map函數(shù)是系統(tǒng)提供得具有映射功能得函數(shù),返回值是一個(gè)迭代對(duì)象
- map python2 傳入什么類型數(shù)據(jù)返回什么類型數(shù)據(jù)
- map python3 傳入什么類型數(shù)據(jù)返回 ..."map"... 類型數(shù)據(jù)
- map(...)
? ? map(function, sequence[, sequence, ...]) -> list
? ? Return a list of the results of applying the function to the items of
? ? the argument sequence(s).? If more than one sequence is given, the
? ? function is called with an argument list consisting of the corresponding
? ? item of each sequence, substituting None for missing values when not all
? ? sequences have the same length.? If the function is None, return a list of
? ? the items of the sequence (or a list of tuples if more than one sequence).
```python
# map 舉例
# 將一個(gè)列表中的元素乘以10熊响,并得到新列表
l1 = [i for i in range(10)]
print(l1)
l2 = []
for i in l1:
? ? l2.append(i * 10)
print(l2)
# map 實(shí)現(xiàn)以上功能
def mulTen(n):
? ? return n * 10
l3 = map(mulTen,l1)
print (l3)
```
?reduce
- 意愿是歸并旨别,縮減
- 把一個(gè)可迭代的對(duì)象最后歸并成一個(gè)結(jié)果
- 對(duì)于函數(shù)參數(shù)要求:必須有兩個(gè)參數(shù),必須有返回結(jié)果
- reduce[1,2,3,4,5] = fun(fun(fun(fun(1,2),3),4),5)
- reduce 需要 functools包
```python
from functools import reduce
# 定義個(gè)操作函數(shù)
def add(x,y):
? ? return x + y
# 對(duì)于列表【1汗茄,2秸弛,3,4洪碳,5递览,6】執(zhí)行add 操作
rst = reduce(add ,[1,2,3,4,5,6])
print (rst)
# 以上reduce可看作下面進(jìn)行運(yùn)算
rst2 =add(add(add(add(add(1,2),3),4),5),6)
print(rst2)
```
filter 函數(shù)
- 過(guò)濾函數(shù):對(duì)一組數(shù)據(jù)進(jìn)行過(guò)濾,符合條件的數(shù)據(jù)會(huì)生成一個(gè)新的列表并返回
- 跟map 相比:
? ? - 相同: 都對(duì)列表的每一個(gè)元素逐一進(jìn)行操作
? ? - 不同: map會(huì)生成一個(gè)跟原來(lái)數(shù)據(jù)相對(duì)應(yīng)的新隊(duì)列
? ? ? ? ? filter 不一定瞳腌,只要符合條件的才會(huì)進(jìn)入新的數(shù)據(jù)集合
? ? - filter函數(shù)怎么寫(xiě):
? ? ? ? - 利用給定函數(shù)進(jìn)行判斷
? ? ? ? - 返回值一定是個(gè)布爾值
? ? ? ? - 調(diào)用格式:filter(f,data),f是過(guò)濾函數(shù)绞铃,data是數(shù)據(jù)
```python
# filter 函數(shù)
# 對(duì)一個(gè)列表,對(duì)其進(jìn)行過(guò)濾嫂侍,偶數(shù)組成一個(gè)新列表
# 需要定義過(guò)濾函數(shù)
# 過(guò)濾函數(shù)要求有輸入儿捧,返回布爾值
def isEven(a):
? ? return a % 2 == 0
l = [1,2,3,4,54,3,2,32,32,32,3,333,44,32,4325]
res = filter(isEven,l)
#返回一個(gè)可迭代對(duì)象
print(res)
print([i for i in res])
```
?高階函數(shù)-排序
- 把一個(gè)序列按照給定的算法進(jìn)行排序
- key: 在排序中對(duì)每一元素進(jìn)行key函數(shù)運(yùn)算,可以理解成按照key函數(shù)定義的邏輯進(jìn)行排序
- python2 和 python3 相差巨大
```python
#排序案例1
a = [12,32,43,543,56,654,6576,5765,765,645,6546645,654645]
al = sorted(a)
ad = sorted(a,reverse=True)
print(al)
print(ad)
```
```python
#排序案例2
a = [-12,2,32,-455,321,32]
# 按照絕對(duì)值進(jìn)行排序
# abs是求絕對(duì)值的意思
# 即按照絕對(duì)值的倒敘進(jìn)行排序
al = sorted(a, key=abs, reverse=True)
print(al)
```
```python
#sorted 排序案例
astr = ['dana','whj','jin','WTt','Zs','sz']
str1 = sorted(astr)
print(str1)
str2 = sorted(astr,key=str.lower)
print(str2)
```
?高階函數(shù)-返回函數(shù)
```python
# 負(fù)責(zé)一點(diǎn)的返回函數(shù)的例子
# args 參數(shù)列表
# myF4 定義函數(shù)挑宠,返回內(nèi)部定義的函數(shù)myF5
# myF5使用了外部變量菲盾,這個(gè)變量是myF4的參數(shù)
def myF4( *args):
? ? def myF5():
? ? ? ? rst = 0
? ? ? ? for n in args:
? ? ? ? ? ? rst += n
? ? ? ? return rst
? ? return myF5
f5 = myF4(1,2,3,4,5,6,7,8,9,10)
f5()
```
```python
f6 = myF4(10,20,30)
f6()
```
閉包(closure)
- 當(dāng)一個(gè)函數(shù)在內(nèi)部定義函數(shù),并且內(nèi)部的函數(shù)應(yīng)用外部函數(shù)的參數(shù)或局部變量各淀,當(dāng)內(nèi)部函數(shù)被作返回值的時(shí)候懒鉴,相關(guān)參數(shù)和變量保存在返回的函數(shù)中,這種結(jié)果碎浇,叫做閉包疗我。
- 上面定義的myF4 是一個(gè)標(biāo)準(zhǔn)的閉包結(jié)構(gòu)
```python
# 閉包常見(jiàn)的坑
def count():
? ? # 定義列表
? ? fs = []
? ? for i in range(1,4):
? ? ? ? # 定義了一個(gè)函數(shù)f
? ? ? ? def f():
? ? ? ? ? ? return i*i
? ? ? ? fs.append(f)
? ? return fs
f1,f2,f3 = count()
print(f1())
print(f2())
print(f3())
```
### 出現(xiàn)問(wèn)題:
- 造成上述情況的原因是,返回函數(shù)引用了變量i,i并非立即執(zhí)行南捂,而是等到三個(gè)函數(shù)都返回的時(shí)候才統(tǒng)一執(zhí)行吴裤,此時(shí)i已經(jīng)變成了3,最終調(diào)用的時(shí)候溺健,都返回的3*3
- 此問(wèn)題描述成:返回閉包時(shí)麦牺,返回函數(shù)不能引用任何循環(huán)變量
- 解決方案:在創(chuàng)建一個(gè)函數(shù)钮蛛,用該函數(shù)的參數(shù)綁定循環(huán)變量的當(dāng)前值,無(wú)論該循環(huán)變量以后如何改變剖膳,已經(jīng)綁定的函數(shù)參數(shù)值不在改變
```python
# 修改上述函數(shù)
def count1():
? ? def f(j):
? ? ? ? def g():
? ? ? ? ? ? return j*j
? ? ? ? return g
? ? fs = []
? ? for i in range(1,4):
? ? ? ? fs.append(f(i))
? ? return fs
f1,f2,f3 = count1()
print(f1())
print(f2())
print(f3)
```
裝飾器(Dercrator)
- python裝飾器就是用于拓展原來(lái)函數(shù)功能的一種函數(shù)魏颓,這個(gè)函數(shù)的特殊之處在于它的返回值也是一個(gè)函數(shù)
- 在不改動(dòng)函數(shù)代碼的基礎(chǔ)上無(wú)限制擴(kuò)展函數(shù)功能的一種機(jī)制,本質(zhì)上講吱晒,裝飾器是一個(gè)返回函數(shù)的高階函數(shù)
- 裝飾器使用:使用@語(yǔ)法甸饱,即在每次要擴(kuò)展到函數(shù)定義前面使用@+函數(shù)名
- 裝飾器先執(zhí)行裝飾器內(nèi)函數(shù),在執(zhí)行被裝飾函數(shù)仑濒。
```python
# 我們要想拓展原來(lái)函數(shù)代碼叹话,最直接的辦法就是侵入代碼里面修改,例如:
import time
def hello():
? ? startTime = time.time()
? ? print("hello")
? ? time.sleep(1)
? ? print("world")
? ? endTime = time.time()
? ? msecs = (endTime - startTime)*1000
? ? print("time is %d ms" %msecs)
hello()
```
- 避免直接侵入原函數(shù)修改墩瞳,但是生效需要再次執(zhí)行函數(shù)
```python
import time
def deco(func):
? ? startTime = time.time()
? ? func()
? ? endTime = time.time()
? ? msecs = (endTime - startTime)*1000
? ? print("time is %d ms" %msecs)
def func():
? ? print("hello")
? ? time.sleep(1)
? ? print("world")
f = func
deco(f)#只有把func()或者f()作為參數(shù)執(zhí)行驼壶,新加入功能才會(huì)生效
```
- 核心代碼區(qū)域有一千萬(wàn)個(gè)func()函數(shù),從func01()到func1kw(),按以上實(shí)現(xiàn)方案喉酌,想要拓展這一千萬(wàn)個(gè)函數(shù)功能热凹,就是要執(zhí)行一千萬(wàn)次deco()函數(shù)。這種方式不可取泪电。
- 實(shí)現(xiàn)一個(gè)最簡(jiǎn)陋的裝飾器般妙,不使用任何語(yǔ)法和高級(jí)語(yǔ)法,看看裝飾器最原始的面貌
- 這里的deco函數(shù)就是最原始的裝飾器相速,它的參數(shù)是一個(gè)函數(shù)碟渺,然后返回值也是一個(gè)函數(shù)。其中作為參數(shù)的這個(gè)函數(shù)func()就在返回函數(shù)wrapper()的內(nèi)部執(zhí)行和蚪。然后在函數(shù)func()前面加上@deco止状,func()函數(shù)就相當(dāng)于被注入了計(jì)時(shí)功能,現(xiàn)在只要調(diào)用func()攒霹,它就已經(jīng)變身為“新的功能更多”的函數(shù)了怯疤。
- 所以這里裝飾器就像一個(gè)注入符號(hào):拓展了原來(lái)函數(shù)的功能既不需要侵入函數(shù)內(nèi)更改代碼,也不需要重復(fù)執(zhí)行原函數(shù)催束。
```python
#既不需要侵入集峦,也不需要函數(shù)重復(fù)執(zhí)行
import time
def deco(func):
? ? def wrapper():
? ? ? ? startTime = time.time()
? ? ? ? func()
? ? ? ? endTime = time.time()
? ? ? ? msecs = (endTime - startTime)*1000
? ? ? ? print("time is %d ms" %msecs)
? ? return wrapper
# 上面定義裝飾器,使用的時(shí)候需要用到@ 抠刺,此符號(hào)是python的語(yǔ)法糖
@deco
def func():
? ? print("hello")
? ? time.sleep(1)
? ? print("world")
f = func #這里f被賦值為func塔淤,執(zhí)行f()就是執(zhí)行func()
f()
```
- 帶有參數(shù)的裝飾器
```python
import time
def deco(func):
? ? def wrapper(a,b):
? ? ? ? startTime = time.time()
? ? ? ? func(a,b)
? ? ? ? endTime = time.time()
? ? ? ? msecs = (endTime - startTime)*1000
? ? ? ? print("time is %d ms" %msecs)
? ? return wrapper
@deco
def func(a,b):
? ? print("hello,here is a func for add :")
? ? time.sleep(1)
? ? print("result is %d" %(a+b))
f = func
f(3,4)
```
- 帶有不定參數(shù)的裝飾器
```python
import time
def deco(func):
? ? def wrapper(*args, **kwargs):
? ? ? ? startTime = time.time()
? ? ? ? func(*args, **kwargs)
? ? ? ? endTime = time.time()
? ? ? ? msecs = (endTime - startTime)*1000
? ? ? ? print("time is %d ms" %msecs)
? ? return wrapper
@deco
def func(a,b):
? ? print("hello速妖,here is a func for add :")
? ? time.sleep(1)
? ? print("result is %d" %(a+b))
@deco
def func2(a,b,c):
? ? print("hello高蜂,here is a func for add :")
? ? time.sleep(1)
? ? print("result is %d" %(a+b+c))
f = func
func2(3,4,5)
f(3,4)
```
- 多個(gè)裝飾器
```python
import time
def deco01(func):
? ? def wrapper(*args, **kwargs):
? ? ? ? print("this is deco01")
? ? ? ? startTime = time.time()
? ? ? ? func(*args, **kwargs)
? ? ? ? endTime = time.time()
? ? ? ? msecs = (endTime - startTime)*1000
? ? ? ? print("time is %d ms" %msecs)
? ? ? ? print("deco01 end here")
? ? return wrapper
def deco02(func):
? ? def wrapper(*args, **kwargs):
? ? ? ? print("this is deco02")
? ? ? ? func(*args, **kwargs)
? ? ? ? print("deco02 end here")
? ? return wrapper
@deco01
@deco02
def func(a,b):
? ? print("hello,here is a func for add :")
? ? time.sleep(1)
? ? print("result is %d" %(a+b))
f = func
f(3,4)
```
?偏函數(shù)(Partial)
- 參數(shù)固定的函數(shù)罕容,相當(dāng)于一個(gè)由特定參數(shù)的函數(shù)體
- functools.partial的作用是:把一個(gè)函數(shù)某些函數(shù)固定备恤,返回一個(gè)新函數(shù)
```python
# 把字符串轉(zhuǎn)換十進(jìn)制數(shù)字
int("12345")
# 求八進(jìn)制的字符串12345稿饰,表示成十進(jìn)制的數(shù)字是多少
int("12345",base=8)
```
```python
# 新建一個(gè)函數(shù),此函數(shù)是默認(rèn)輸入的字符串是16進(jìn)制數(shù)字
# 把此字符串返回十進(jìn)制的數(shù)字
def int16(x,base=16):
? ? return int(x,base)
int16("12345")
```
```python
import functools
int16 = functools.partial(int,base=16)
int16("12345")
```