遞歸
如果用上面的做遞歸的定義,總感覺有點調侃,來個嚴肅的(選自維基百科):
遞歸(英語: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
幾個特殊的函數
filter
、map
、reduce
、lambda
、yield
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;”