回調函數、遞歸函數


回調函數、遞歸函數

回調函數

回調函數又叫函數回調,指的是將函數作為參數傳遞到另外的函數中執行。例如將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

enter description here
上圖是有三個函數內存地址,下面我們開始運行第一個函數調用

首先以位置傳參到另外的函數變量中,此時num = 1 fun = f1 函數內存地址指向剛才定義f1函數的內存地址,再往下運行就會實現print 這是f1函數 1
enter description here

遞歸函數

在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數,下面例子就是調用自身。

#例子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)

enter description here

每一次函數調用都會產生一個屬於它自己的名稱空間,如果一直調用下去,就會造成名稱空間占用太多內存的問題。
enter description here

當跳出判斷后開始return 此時他會return什么呢?
enter description here

func(1-1)已經被return 接下來會return什么?
enter description here

接着就會return func(2-1) return func(3-1) 最終結果是 return func(3)
enter description here

相信看到這里都有點蒙,這么想,大部分人在做事情的時候,中斷第一件事,被安排去做第二件事的時候,就會把第一件事后續的事情給忘記,如果在做第二件事的時候,又被中斷,被安排去做第三件事,就會把第一件、第二件要做的后續的事情給忘記......,這就是不理解遞歸函數的原因。

下面再來一個例子3

def age(n):
    if n == 1:
        return 40
    else:
        return age(n-1)+2

print(age(4))

詳解一下上面代碼的運行過程
enter description here

在調用函數本身時,它之后的代碼並沒有結束,而是在等待條件為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 代碼運行后會出現錯誤
enter description here
使用遞歸函數需要注意防止棧溢出。在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出。於是python為了杜絕此類現象,強制的將遞歸層數控制在了997,也可以進行修改默認遞歸深度,如果用997層遞歸都沒有解決的問題要么是不適合使用遞歸來解決。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM