遞歸
- 如果一個函數在內部調用了自身,這個函數稱為遞歸函數
- 遞歸條件:
1.子問題與原始問題為同樣的事,且更為簡單
2.不能無限制的調用本身,要有個出口,化簡為非遞歸狀況處理
- 高斯求和問題:
def sum_number(n):
total = 0
for i in range(0,n+1):
total += i
sum_number(100)
如果用遞歸來寫:
def sum_number(n):
if n<=0:
return 0
return n+sum_number(n-1)
sum_number(100)
- 遞歸核心:每一次遞歸,整體問題都要比原來減小,并且遞歸到一定層次時,要能直接給出結果。
- 基本步驟:
1.初始化算法。遞歸程序通常需要一個開始時使用的種子值,可以向函數傳遞參數,或者提供一個入口函數,這個函數是非遞歸的,但可以為遞歸計算設置種子值。
2.檢查要處理的當前值是否已經與基線條件匹配。如果匹配,則進行處理并返回值
3.使用更小的或者更簡單的子問題來重新定義答案。
4.對子問題進行算法
5.將結果合并入答案的表達式
6.返回結果
- 注意:使用遞歸函數要放置遞歸深度溢出,在Python中,通常情況下,這個深度為1000層,超過將拋出異常。在計算機中,函數遞歸調用是通過棧(stack)這種數據結構實現的,每當進入一個遞歸時,棧就會加一層,每當函數返回一次,棧就減少一層。由于棧的大小不是無線的,所以,遞歸調用的次數過多,會導致棧溢出。
尾遞歸
- 簡介:
1.當遞歸調用是整個函數體最后執行的語句且它的返回值不屬于表達式的一部分時,就是尾遞歸
2.特點:在回歸過程中不做任何操作。
3.原理:當編譯器檢測到一個函數調用是尾遞歸的時候,它就覆蓋當前的活動記錄而不是在棧中去創建一個新的。實際運行效率更高。
- 以尾遞歸方式實現階乘函數:
def facttail(n,res):
if n < 0:
return 0
elif n == 0:
return 1
elif n == 1:
return res
else:
return facttail(n-1,n*res)
只是比遞歸多了一個參數res。res(初始化為1)維護遞歸層次的深度。
匿名函數
Python用lambda關鍵字來創建匿名函數。所謂匿名,即不在用def語句來定義一個標準函數
1.lambda只是一個表達式,而不是一個代碼塊,函數體比def簡單
2.僅僅能在lambda表達式中封裝有限的邏輯
3.lambda函數擁有自己的命名空間
4.形式:lambda 參數:表達式
5.匿名函數可以賦值給一個變量,在利用變量來調用該函數
>>>f = lambda x:x*x
>>>f(6)
36
6.可以把匿名函數作為別的函數返回值返回
推導式
1.列表推導式
- 快速生成列表:
lis = [x*x for x in range(1,11)]
相當于:
lis = []
for x in range(1,11):
lis.append(x*x)
- 增加條件語句
>>>[x*x for x in range(1,11) if x%2 == 0]
[4,16,36,64,100]
- 多重循環
>>>[a+b for a in '123' for b in 'abc']
['1a','1b','1c','2a','2b','2c','3a','3b','3c']
2.字典推導式
>>> dic = {x:x**2 for x in (2,4,6)}
{2:4,4:16,6:36}
>>> type(dic)
<class 'dict'>
中間的:
表示左邊是key右邊是value
3.集合推導式
大括號除了能作字典推導式,還可以用作集合推導式。細微差別
>>> a = {x for x in 'abcrabiaac' if x not in 'abc'}
>>> a
{'r','i'}
>>> type(a)
<class 'set'>
4.沒有元組推導式,沒有元組推導式,沒有元組推導式
面試題:
看下面代碼輸出結果是什么?為什么?
result = [lambda x:x+i for i in range(10)]
print(result[0](10))
結果:result0~9的結果都是19
函數具有調用時才查找變量的特性。在你沒有調用它之前,不不會保存也不關心它內部變量的具體值。只有當你調用它的時候,才回去逐一找變量的具體值。
result[0]被調用的時候,變量i已經循環完畢,變成9了。
- 想要i循環的值怎么辦?
不要引用上層變量,把i直接傳進來
result = [lambda x,i=i:x+i for i in range(10)]
迭代器
迭代器是一種可以被遍歷的對象,并且能作用與next()函數。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。
迭代器只能往后遍歷,不能回溯。兩個方法:iter()
和next()
- 創建
lis = [1,2,3]
it = iter(lis) //創建
next(it) //取出下一個元素
- 迭代器(Iterator)和可迭代(Iterable)的區別
1.凡是可用作for循環的對象都是可迭代類型
2.凡是作用于next()函數的對象都是迭代器類型
3.list,dict,str等是可迭代的但不是迭代器,因為next()函數無法調用,可以通過iter()函數轉換成迭代器
4.for循環的本質就是不斷調用next()函數實現的。