回調函數、遞歸函數 回調函數 回調函數又叫函數回調,指的是將函數作為參數傳遞到另外的函數中執行。例如將A函數作為參數傳遞到B函數。然後在B函數中執行A函數。這種做法的好處是在函數被定義之前就可以使用函數,或者對於其他程式提供的API(可看成函數)進行調用。概念比較抽象,看下麵例子: 結果 上圖是有三 ...
回調函數、遞歸函數
回調函數
回調函數又叫函數回調,指的是將函數作為參數傳遞到另外的函數中執行。例如將A函數作為參數傳遞到B函數。然後在B函數中執行A函數。這種做法的好處是在函數被定義之前就可以使用函數,或者對於其他程式提供的API(可看成函數)進行調用。概念比較抽象,看下麵例子:
def func(num,fun):
fun(num)
def f1(x):
print("這是f1函數",x)
def f2(x):
print("這是f2函數",x)
func(1,f1)
func("hello",f2)
結果
這是f1函數 1
這是f2函數 hello
上圖是有三個函數記憶體地址,下麵我們開始運行第一個函數調用
首先以位置傳參到另外的函數變數中,此時num = 1 fun = f1 函數記憶體地址指向剛纔定義f1函數的記憶體地址,再往下運行就會實現print 這是f1函數 1
遞歸函數
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數,下麵例子就是調用自身。
#例子1
def foo(n):
print(n)
n += 1
foo(n)
foo(1)
運行下麵代碼
#例子2
def func(num):
print(num)
if num > 0:
func(num -1)
else:
print('--------')
return num
res = func(3)
print(res)
每一次函數調用都會產生一個屬於它自己的名稱空間,如果一直調用下去,就會造成名稱空間占用太多記憶體的問題。
當跳出判斷後開始return 此時他會return什麼呢?
func(1-1)已經被return 接下來會return什麼?
接著就會return func(2-1) return func(3-1) 最終結果是 return func(3)
相信看到這裡都有點蒙,這麼想,大部分人在做事情的時候,中斷第一件事,被安排去做第二件事的時候,就會把第一件事後續的事情給忘記,如果在做第二件事的時候,又被中斷,被安排去做第三件事,就會把第一件、第二件要做的後續的事情給忘記......,這就是不理解遞歸函數的原因。
下麵再來一個例子3
def age(n):
if n == 1:
return 40
else:
return age(n-1)+2
print(age(4))
詳解一下上面代碼的運行過程
在調用函數本身時,它之後的代碼並沒有結束,而是在等待條件為False 時,再接著執行之後的代碼,同一個顏色的print()語句等待對應顏色的函數。
Starting var:.. n = 4
23:14:57.157933 call 4 def age(n):
23:14:57.157933 line 5 if n == 1:
23:14:57.157933 line 8 return age(n-1)+2
Starting var:.. n = 3
23:14:57.157933 call 4 def age(n):
23:14:57.157933 line 5 if n == 1:
23:14:57.157933 line 8 return age(n-1)+2
Starting var:.. n = 2
23:14:57.157933 call 4 def age(n):
23:14:57.158934 line 5 if n == 1:
23:14:57.158934 line 8 return age(n-1)+2
Starting var:.. n = 1
23:14:57.158934 call 4 def age(n):
23:14:57.158934 line 5 if n == 1:
23:14:57.158934 line 6 return 40
23:14:57.158934 return 6 return 40
Return value:.. 40
23:14:57.158934 return 8 return age(n-1)+2
Return value:.. 42
23:14:57.158934 return 8 return age(n-1)+2
Return value:.. 44
23:14:57.158934 return 8 return age(n-1)+2
Return value:.. 46
看上面的過程,當n=1時,直接返回40 此時記憶體中 age(1) 就產生了。下麵它就會把倒數第二件事做完,那就是age(2-1)+2。現在記憶體中已經有age(1)=40 了,那麼age(1)+2=age(2)=42,且age(2)存在記憶體中,以此類推!
age(3-1)+2=age(3)=44
age(4-1)+2=age(4)=46
最終返回值是46
例子1 代碼運行後會出現錯誤
使用遞歸函數需要註意防止棧溢出。在電腦中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出。於是python為了杜絕此類現象,強制的將遞歸層數控制在了997,也可以進行修改預設遞歸深度,如果用997層遞歸都沒有解決的問題要麼是不適合使用遞歸來解決。