負(fù)基礎(chǔ)小白學(xué)習(xí)廖雪峰python教程記錄(四)函數(shù)式編程

高階函數(shù)

前言

變量可以指向函數(shù)

>>> f = abs

>>> f(-10)

10

函數(shù)名也是變量

>>> abs = 10

>>> abs(-10)

Traceback (most recent call last):?

?File"<stdin>", line1, in <module>

Type Error:'int' object is not callable


傳入函數(shù)

一個(gè)函數(shù)就可以接收另一個(gè)函數(shù)作為參數(shù)庶喜,這種函數(shù)就稱之為高階函數(shù)

def add(x, y, f):

????return f(x) + f(y)


map/reduce

map

map()函數(shù)接收兩個(gè)參數(shù)椭微,一個(gè)是函數(shù),一個(gè)是Iterable牲蜀,map將傳入的函數(shù)依次作用到序列的每個(gè)元素革砸,并把結(jié)果作為新的Iterator返回

>>> def f(x):

...? ? return x*x

...

>>> r=map(f,[1,2,3,4,5,6,7,8,9])

>>> list(r)

[1, 4, 9, 16, 25, 36, 49, 64, 81]


>>> list(map(str,[1,2,3,4,5,6,7,8,9]))

['1', '2', '3', '4', '5', '6', '7', '8', '9']


reduce

reduce把一個(gè)函數(shù)作用在一個(gè)序列[x1, x2, x3, ...]上除秀,這個(gè)函數(shù)必須接收兩個(gè)參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算算利。

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

>>> from functools import reduce

>>> def add(x,y):

...? ? return x+y

...

>>> reduce(add,[1,3,5,7,9])

25


把序列[1, 3, 5, 7, 9]變換成整數(shù)13579册踩,reduce用法:

>>> from functools import reduce

>>> def fn(x,y):

...? ? return x*10+y

...

>>> reduce(fn,[1,3,5,7,9])

13579


練習(xí)

第一題:
>>> def normalize(name):

...? ? a= name[0].upper()

...? ? b= name[1:].lower()

...? ? name=a+b

...? ? return name

...

>>> L1 = ['adam', 'LISA', 'barT']

>>> L2 = list(map(normalize, L1))

>>> print(L2)

['Adam', 'Lisa', 'Bart']


第二題:

>>> def prod(x,y):

...? ? return x*y

...

>>> reduce(prod,[3,5,7,9])


第三題:


filter

filter()函數(shù)用于過濾序列

例如效拭,在一個(gè)list中暂吉,刪掉偶數(shù),只保留奇數(shù):

>>> def is_odd(n):

...? ? return n%2==1

...

>>> list(filter(is_odd,[1,2,4,5,6,9,10,15]))

[1, 5, 9, 15]

用filter求素?cái)?shù)

計(jì)算素?cái)?shù)的一個(gè)方法是埃氏篩法缎患。

首先慕的,列出從2開始的所有自然數(shù),構(gòu)造一個(gè)序列挤渔。

取序列的第一個(gè)數(shù)2肮街,它一定是素?cái)?shù),然后用2把序列的2的倍數(shù)篩掉

取新序列的第一個(gè)數(shù)3判导,它一定是素?cái)?shù)嫉父,然后用3把序列的3的倍數(shù)篩掉

取新序列的第一個(gè)數(shù)5,然后用5把序列的5的倍數(shù)篩掉

不斷篩下去眼刃,就可以得到所有的素?cái)?shù)绕辖。

用Python來實(shí)現(xiàn)這個(gè)算法,可以先構(gòu)造一個(gè)從3開始的奇數(shù)序列:

def_odd_iter():

????n =1

????while True:?

? ? ? ? n = n +2

????????yield n

然后定義一個(gè)篩選函數(shù):

def_not_divisible(n):

????return lambda x: x % n >0

最后擂红,定義一個(gè)生成器仪际,不斷返回下一個(gè)素?cái)?shù):

def primes():

????yield 2?

????it = _odd_iter()? ? # 初始序列

? ? whileTrue:?

? ? ? ? n = next(it)? ? ? # 返回序列的第一個(gè)數(shù)

????????yield n?

? ? ? ? it = filter(_not_divisible(n), it)? ? # 構(gòu)造新序列

這個(gè)生成器先返回第一個(gè)素?cái)?shù)2,然后昵骤,利用filter()不斷產(chǎn)生篩選后的新的序列树碱。由于primes()也是一個(gè)無限序列,所以調(diào)用時(shí)需要設(shè)置一個(gè)退出循環(huán)的條件:

# 打印1000以內(nèi)的素?cái)?shù):

for n in primes():

????if n <1000:?

? ? ? ? print(n)

????else:

????????break


練習(xí)

回?cái)?shù)是指從左向右讀和從右向左讀都是一樣的數(shù)涉茧,例如12321赴恨,909。請(qǐng)利用filter()篩選出回?cái)?shù):

def?is_palindrome(n):

????return?str(n)?==?str(n)[::-1]


sorted

sorted()也是一個(gè)高階函數(shù)伴栓。用sorted()排序的關(guān)鍵在于實(shí)現(xiàn)一個(gè)映射函數(shù)伦连。

>>> sorted([36,5,-12,9,-21])

[-21, -12, 5, 9, 36]

絕對(duì)值排序:

>>> sorted([36,5,-12,9,-21],key=abs)

[5, 9, -12, -21, 36]

字符串排序雨饺,按照ASCII的大小比較的,由于'Z' < 'a'惑淳,結(jié)果额港,大寫字母Z會(huì)排在小寫字母a的前面:

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

['Credit', 'Zoo', 'about', 'bob']

忽略大小寫的排序:

>>> 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']


練習(xí)

L是用tuple來表示一對(duì)名字和分?jǐn)?shù)的。

key是用來進(jìn)行比較的元素歧焦,只有一個(gè)參數(shù)移斩,具體的函數(shù)的參數(shù)就是取自于可迭代對(duì)象中,指定可迭代對(duì)象中的一個(gè)元素來進(jìn)行排序绢馍。

具體的函數(shù)的參數(shù)就是取自于可迭代對(duì)象中向瓷,指定可迭代對(duì)象中的一個(gè)元素來進(jìn)行排序。

那么我們看代碼中的t表示啥舰涌,表示的是不是可迭代對(duì)象(list)中的一個(gè)元素(tuple類型)

一個(gè)tuple的表示形式是('名字':分?jǐn)?shù))?? ('Bob': 75)

?那么t[0]和t[1]猖任,前一個(gè)名字,后一個(gè)分?jǐn)?shù)瓷耙。轉(zhuǎn)換到key中去就是按照名字排序朱躺,和按照分?jǐn)?shù)排序。

>>> L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

>>> def by_name(t):

...? ? ? return t[0]

...

>>> sorted(L, key=by_name)


>>> def by_score(t):

...? ? return -t[1]? ? ? ?#成績(jī)降序排列

...

>>> sorted(L, key=by_score)

[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]


返回函數(shù)

函數(shù)作為返回值

通常情況下的求和:

def calc_sum(*args):

????ax =0

????for n in args:?

????????ax = ax + n

????return ax

需要再計(jì)算的話搁痛,可以不返回求和的結(jié)果长搀,而是返回求和的函數(shù):

def lazy_sum(*args):

????def sum():

????????ax =0

????????for n in args:?

????????????ax = ax + n

????????????return ax

????return sum

在函數(shù)lazy_sum中又定義了函數(shù)sum,并且鸡典,內(nèi)部函數(shù)sum可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量源请,當(dāng)lazy_sum返回函數(shù)sum時(shí),相關(guān)參數(shù)和變量都保存在返回的函數(shù)中彻况。(閉包程序)


閉包

返回函數(shù)不要引用任何循環(huán)變量巢钓,或者后續(xù)會(huì)發(fā)生變化的變量!A贫狻!硫朦!

>>> def count():

...? ? fs=[]

...? ? for i in range(1,4):

...? ? ? ? ? ? def f():

...? ? ? ? ? ? ? ? ? ? return i*i

...? ? ? ? ? ? fs.append(f)

...? ? return fs

...

>>> f1,f2,f3=count()

>>> f1()

9

>>> f2()

9

>>> f3()

9

輸出結(jié)果不是1贷腕,4,9咬展。原因就在于返回的函數(shù)引用了變量i泽裳,但它并非立刻執(zhí)行。等到3個(gè)函數(shù)都返回時(shí)破婆,它們所引用的變量i已經(jīng)變成了3涮总,因此最終結(jié)果為9。

如果一定要引用循環(huán)變量怎么辦祷舀?方法是再創(chuàng)建一個(gè)函數(shù)瀑梗,用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值烹笔,無論該循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變:

>>> def count():

...? ? 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=count()

>>> f1()

1

>>> f2()

4

>>> f3()

9


作業(yè)

暫缺



匿名函數(shù)

>>> list(map(lambda x: x*x,[1,2,3,4,5,6,7,8,9]))

[1, 4, 9, 16, 25, 36, 49, 64, 81]

關(guān)鍵字lambda表示匿名函數(shù)怜浅,冒號(hào)前面的x表示函數(shù)參數(shù)油湖。匿名函數(shù)只能有一個(gè)表達(dá)式长捧,不用寫return,返回值就是該表達(dá)式的結(jié)果允蜈。

匿名函數(shù)沒有名字,不必?fù)?dān)心函數(shù)名沖突蒿柳。此外饶套,匿名函數(shù)也是一個(gè)函數(shù)對(duì)象,也可以把匿名函數(shù)賦值給一個(gè)變量垒探,再利用變量來調(diào)用該函數(shù):

>>> f=lambda x: x*x

>>> f

<function <lambda> at 0x000001CE0FDCEE50>

>>> f(6)

36

也可以把匿名函數(shù)作為返回值返回妓蛮,比如:

def build(x, y):

????return lambda: x * x + y * y


作業(yè)

用匿名函數(shù)改寫:

def is_odd(n):

? ? return n % 2 == 1

L = list(filter(is_odd, range(1, 20)))

改寫后:

L=list(filter(lambda n: n%2==1, range(1, 20)))

print(L)


裝飾器

函數(shù)對(duì)象可以被賦值給變量,所以叛复,通過變量也能調(diào)用該函數(shù)仔引。

>>> def now():

...? ? print('2015-3-25')

...

>>> f=now

>>> f()

2015-3-25

函數(shù)對(duì)象有一個(gè)__name__屬性,可以拿到函數(shù)的名字:

>>> now.__name__? ? ? ? #兩個(gè)下劃線name兩個(gè)下劃線

'now'

>>> f.__name__

'now'

在代碼運(yùn)行期間動(dòng)態(tài)增加功能的方式褐奥,稱之為“裝飾器”(Decorator)

>>> def log(func):

...? ? def wrapper(*arg,**kw):

...? ? ? ? ? ? print('call %s():' % func.__name__)

...? ? ? ? ? ? return func(*arg,**kw)

...? ? return wrapper

借助Python的@語法咖耘,把decorator置于函數(shù)的定義處

>>> @log

... def now():

...? ? print('2015-3-25')

相當(dāng)于執(zhí)行了語句:now =log(now)

調(diào)用now()函數(shù),不僅會(huì)運(yùn)行now()函數(shù)本身撬码,還會(huì)在運(yùn)行now()函數(shù)前打印一行日志:

>>> now()

call now():

2015-3-25


>>> def log(text):

...? ? def decorator(func):

...? ? ? ? ? ? def wrapper(*args,**kw):

...? ? ? ? ? ? ? ? ? ? print('%s %s():' % (text, func.__name__))

...? ? ? ? ? ? ? ? ? ? return func(*args,**kw)

...? ? ? ? ? ? return wrapper

...? ? return decorator

這個(gè)3層嵌套的decorator用法如下:

>>> @log('execute')

... def now():

...? ? print('2015-3-25')

執(zhí)行結(jié)果如下:

>>> now()

execute now():

2015-3-25

此時(shí):

>>> now.__name__

'wrapper'

import functools

>>> import functools

>>> def log(func):

...? ? @functools.wraps(func)

...? ? def wrapper(*args, **kw):

...? ? ? ? ? ? print('claa %s():' % func.__name__)

...? ? ? ? ? ? return func(*args,**kw)

...? ? return wrapper

或者針對(duì)帶參數(shù)的decorator:

>>> import functools

>>> def log(text):

...? ? def decorator(func):

...? ? ? ? ? ? @functools.wrap(func)

...? ? ? ? ? ? def wrapper(*args, **kw):

...? ? ? ? ? ? ? ? ? ? print('%s %s():' % (text, func.__name__))

...? ? ? ? ? ? ? ? ? ? return func(*args, **kw)

...? ? ? ? ? ? return wrapper

...? ? return decorator

作業(yè)

暫缺


偏函數(shù)

把一個(gè)函數(shù)的某些參數(shù)給固定锥埂(也就是設(shè)置默認(rèn)值),返回一個(gè)新的函數(shù)呜笑,調(diào)用這個(gè)新函數(shù)會(huì)更簡(jiǎn)單夫否。

通過設(shè)定參數(shù)的默認(rèn)值,可以降低函數(shù)調(diào)用的難度叫胁。而偏函數(shù)也可以做到這一點(diǎn)凰慈。f

unctools.partial就是幫助我們創(chuàng)建一個(gè)偏函數(shù)的,不需要我們自己定義int2()驼鹅,可以直接使用下面的代碼創(chuàng)建一個(gè)新的函數(shù)int2:

>>> import functools

>>> int2=functools.partial(int, base=2)

>>> int('1000000')

1000000

>>> int2('1000000')

64

僅僅是把base參數(shù)重新設(shè)定默認(rèn)值為2微谓,但也可以在函數(shù)調(diào)用時(shí)傳入其他值:

>>> int2('1000000', base=10)

1000000


創(chuàng)建偏函數(shù)時(shí),實(shí)際上可以接收函數(shù)對(duì)象输钩、*args和**kw這3個(gè)參數(shù)豺型,當(dāng)傳入:

int2 = functools.partial (int, base=2)

實(shí)際上固定了int()函數(shù)的關(guān)鍵字參數(shù)base,也就是:

int2('10010')

相當(dāng)于:

kw = {'base':2}

int('10010', **kw)

傳入:

max2 =functools.partial(max,10)

實(shí)際上會(huì)把10作為*args的一部分自動(dòng)加到左邊买乃,也就是:

max2(5, 6, 7)

args = (10, 5, 6, 7)

max(*args)

結(jié)果為10姻氨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市剪验,隨后出現(xiàn)的幾起案子肴焊,更是在濱河造成了極大的恐慌前联,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抖韩,死亡現(xiàn)場(chǎng)離奇詭異蛀恩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)茂浮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門双谆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人席揽,你說我怎么就攤上這事顽馋。” “怎么了幌羞?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵寸谜,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我属桦,道長(zhǎng)熊痴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任聂宾,我火速辦了婚禮果善,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘系谐。我一直安慰自己巾陕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布纪他。 她就那樣靜靜地躺著鄙煤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茶袒。 梳的紋絲不亂的頭發(fā)上梯刚,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音薪寓,去河邊找鬼乾巧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛预愤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咳胃,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼植康,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了展懈?” 一聲冷哼從身側(cè)響起销睁,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤供璧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后冻记,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睡毒,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年冗栗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了演顾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隅居,死狀恐怖钠至,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胎源,我是刑警寧澤棉钧,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站涕蚤,受9級(jí)特大地震影響宪卿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜万栅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一佑钾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧申钩,春花似錦次绘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至义黎,卻和暖如春禾进,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背廉涕。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工泻云, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狐蜕。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓宠纯,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親层释。 傳聞我的和親對(duì)象是個(gè)殘疾皇子婆瓜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容