Python 函數4

遞歸

如果用上面的做遞歸的定義,總感覺有點調侃,來個嚴肅的(選自維基百科):

遞歸(英語:Recursion),又譯為遞回,在數學與計算機科學中,是指在函數的定義中使用函數自身的方法。

根據斐波那契數列的定義,可以直接寫成這樣的斐波那契數列遞歸函數。

#!/usr/bin/env python
# coding=utf-8

def fib(n):
    """
    This is Fibonacci by Recursion.
    """
    if n==0:
        return 0
    elif n==1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

if __name__ == "__main__":
    f = fib(10)
    print f

fib(n-1) + fib(n-2)就是又調用了這個函數自己,實現遞歸。為了明確遞歸的過程,下面走一個計算過程(考慮到次數不能太多,就讓n=3)

1. n=3,fib(3),自然要走return fib(3-1) + fib(3-2)分支
2. 先看fib(3-1),即fib(2),也要走else分支,于是計算fib(2-1) + fib(2-2)
3. fib(2-1)即fib(1),在函數中就要走elif分支,返回1,即fib(2-1)=1。同理,容易得到fib(2-2)=0。將這兩個值返回到上面一步。得到fib(3-1)=1+0=1
4. 再計算fib(3-2),就簡單了一些,返回的值是1,即fib(3-2)=1
5. 最后計算第一步中的結果:fib(3-1) + fib(3-2) = 1 + 1 = 2,將計算結果2作為返回值

從而得到fib(3)的結果是2。

從上面的過程中可以看出,每個遞歸的過程,都是向著最初的已知條件a0=0,a1=1方向挺近一步,直到通過這個最底層的條件得到結果,然后再一層一層向上回饋計算機結果。

其實,上面的代碼有一個問題。因為a0=0,a1=1是已知的了,不需要每次都判斷一邊。所以,還可以優(yōu)化一下。優(yōu)化的基本方案就是初始化最初的兩個值。

#!/usr/bin/env python
# coding=utf-8

"""
the better Fibonacci
"""
meno = {0:0, 1:1}    #初始化

def fib(n):
    if not n in meno:    #如果不在初始化范圍內
        meno[n] = fib(n-1) + fib(n-2)
    return meno[n]

if __name__ == "__main__":
    f = fib(10)
    print f

#運行結果
$ python 20402.py 
55

幾個特殊的函數

filtermapreducelambdayield

lambda

例子:講list中每個數字增加3,并輸出到新的list

>>> def add(x):     #定義一個函數,將輸入的變量增加3,然后返回增加之后的值
...     x += 3
...     return x
... 
>>> numbers = range(10)
>>> numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  #有這樣一個list,想讓每個數字增加3,然后輸出到一個新的list中

>>> new_numbers = []
>>> for i in numbers:
...     new_numbers.append(add(i))  #調用add()函數,并append到list中
... 
>>> new_numbers
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

在這個例子中,add()只是一個中間操作。當然,上面的例子完全可以用別的方式實現。比如:

>>> numbers = range(10)
>>> new_numbers = [ i+3 for i in numbers ]
>>> new_numbers
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

使用lambda實現,如下:

# 簡單的例子
>>> lam = lambda x:x+3
>>> lam(1)
4
>>> lam(2)
5
>>> lam = lambda x:x*3
>>> lam(2)
6
>>> lam = lambda x,y:x*y
>>> lam(2,3)
6

# 實現上述方法:
>>> numbers = range(10)
>>> lam = lambda x:x+3
>>> n2 = []
>>> for i in numbers:
...     n2.append(lam(i))
... 
>>> n2
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

通過上面例子,總結一下lambda函數的使用方法:

  • 在lambda后面直接跟變量
  • 變量后面是冒號
  • 冒號后面是表達式,表達式計算結果就是本函數的返回值
lambda arg1, arg2, ...argN : expression using arguments

要特別提醒看官:雖然lambda 函數可以接收任意多個參數 (包括可選參數) 并且返回單個表達式的值,但是lambda 函數不能包含命令,包含的表達式不能超過一個。不要試圖向 lambda 函數中塞入太多的東西;如果你需要更復雜的東西,應該定義一個普通函數,然后想讓它多長就多長。

就lambda而言,它并沒有給程序帶來性能上的提升,它帶來的是代碼的簡潔。比如,要打印一個list,里面依次是某個數字的1次方,二次方,三次方,四次方。用lambda可以這樣做:

>>> lamb = [ lambda x:x,lambda x:x**2,lambda x:x**3,lambda x:x**4 ]
>>> for i in lamb:
...     print i(3),
... 
3 9 27 81   

map

map()是python的一個內置函數,它的基本樣式是:

map(func,seq)

func是一個函數,seq是一個序列對象。在執(zhí)行的時候,序列對象中的每個元素,按照從左到右的順序,依次被取出來,并塞入到func那個函數里面,并將func的返回值依次存到一個list中。

>>> items = [1,2,3,4,5]
>>> squared = []
>>> for i in items:
...     squared.append(i**2)
... 
>>> squared
[1, 4, 9, 16, 25]

>>> def sqr(x): return x**2
... 
>>> map(sqr,items)
[1, 4, 9, 16, 25]

>>> map(lambda x: x**2, items)
[1, 4, 9, 16, 25]

>>> [ x**2 for x in items ]     #這個我最喜歡了,一般情況下速度足夠快,而且可讀性強
[1, 4, 9, 16, 25]

理解要點:

  • 對iterable中的每個元素,依次應用function的方法(函數)(這本質上就是一個for循環(huán))。
  • 將所有結果返回一個list。
  • 如果參數很多,則對那些參數并行執(zhí)行function。

例如:

>>> lst1 = [1,2,3,4,5]
>>> lst2 = [6,7,8,9,0]
>>> map(lambda x,y: x+y, lst1,lst2)     #將兩個列表中的對應項加起來,并返回一個結果列表
[7, 9, 11, 13, 5]

請看官注意了,上面這個例子如果用for循環(huán)來寫,還不是很難,如果擴展一下,下面的例子用for來改寫,就要小心了:

>>> lst1 = [1,2,3,4,5]
>>> lst2 = [6,7,8,9,0]
>>> lst3 = [7,8,9,2,1]
>>> map(lambda x,y,z: x+y+z, lst1,lst2,lst3)
[14, 17, 20, 15, 6]

reduce

>>> reduce(lambda x,y: x+y,[1,2,3,4,5]
15

原來map是上下運算,reduce是橫著逐個元素進行運算。

為了鍛煉思維,看這么一個問題,有兩個list,a = [3,9,8,5,2],b=[1,4,9,2,6],計算:a[0]b[0]+a[1]b[1]+...的結果。

>>> a
[3, 9, 8, 5, 2]
>>> b
[1, 4, 9, 2, 6]

>>> zip(a,b)        #復習一下zip,下面的方法中要用到
[(3, 1), (9, 4), (8, 9), (5, 2), (2, 6)]

>>> sum(x*y for x,y in zip(a,b))    #解析后直接求和
133

>>> new_list = [x*y for x,y in zip(a,b)]    #可以看做是上面方法的分布實施

>>> #這樣解析也可以:new_tuple = (x*y for x,y in zip(a,b))
>>> new_list
[3, 36, 72, 10, 12]
>>> sum(new_list)     #或者:sum(new_tuple)
133

>>> reduce(lambda sum,(x,y): sum+x*y,zip(a,b),0)    #這個方法是在耍酷呢嗎?
133

>>> from operator import add,mul            #耍酷的方法也不止一個
>>> reduce(add,map(mul,a,b))
133

>>> reduce(lambda x,y: x+y, map(lambda x,y: x*y, a,b))  #map,reduce,lambda都齊全了,更酷嗎?
133

filter

通過下面代碼體會:

>>> numbers = range(-5,5)
>>> numbers
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]

>>> filter(lambda x: x>0, numbers) 
[1, 2, 3, 4]

>>> [x for x in numbers if x>0]     #與上面那句等效
[1, 2, 3, 4]

>>> filter(lambda c: c!='i', 'qiwsir')  #能不能對應上面文檔說明那句話呢?
'qwsr'                                  #“If iterable is a string or a tuple, the result also has that type;”
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,555評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內容