python函數基礎:嵌套函數、作用域、匿名函數、遞歸函數
嵌套函數:
1. 函數內部可以再定義函數
2. 函數只有被調用之後才會執行
看如下代碼:
age = 18 def func1(): age = 22 print(age) def func2(): age = 28 # 如果這個age沒有被賦值,它會先向它的父級(func1)裏面找,如果父級也沒有就再向它的爺爺級(全局的age)找。 # 一層一層由內向外找 print(age) func2() func1() # 輸出結果: #22 #28
註: 函數內部的變量都叫局部變量,只不過局部變量之間也有等級關系
#情景1: age = 18 def func1(): def func2(): print(age) age = 22 # age=22 依然是func1裏面的變量 func2() #程序從上到下運行到這一步的時候 age已經在函數內被賦值為22 func1() #輸出結果: # 22 #情景2: age = 18 def func1(): def func2(): print(age) func2() #程序由上到下運行到這一步時,由於func2中沒有age,func2會向上一級找,找到了func1中的age=22,但由於變量需要先定義後使用(定於放在使用前面),所以程序會報錯。例如情景3age = 22 # age =22依然是函數func1裏面的變量 func1() # 輸出結果會報錯。 #情景3: age = 18 def func1(): def func2(): print(age2) func2() age2 = 22 func1() # 輸出結果會報錯。 #情景4: age = 18 def func1(): global age #程序執行到這一步的時候,age已經被聲明成了全局變量,並被賦值為18 def func2(): print(age) #執行到這一步的時候age直接調用age這個全局變量func2() age = 22 # 程序執行到這一步的時候age這個全局變量又被賦值成了22 func1() print(age) # 輸出結果: # 18 # 22 #情景5: age = 18 def func1(): global age #到這一步age被聲明成全局變量,並且此時的值還是18 age = 22 # 到這一步時age又被重新賦值為22 def func2(): print(age) func2() func1() #輸出結果: # 22 #情景6: age = 18 def func1(): global age #執行到這一步是age還是18 def func2(): print(age) #執行到這一步的時候age已經是22了 age = 22 # age這個全局變量 在func2調用之前又被改成了22 func2() func1() # 輸出結果: # 22
註:這幾種情況用於分析,實際生產中很少用。
作用域:
在Python中一個函數的就是一個作用域,局部變量其實是放在它的作用域中
age = 18 def func1(): age = 22 def func2(): print(age) return func2 #func2沒加括號,返回的是這個函數名 val= func1() print(val) #打印的是函數名 val() #val就是func2, 此時會執行 # 輸出結果: # <function func1.<locals>.func2 at 0x0000009F6AEAB9D8> # 22 #雖然是在外部執行,但依然是通過其定義域的關系去調用,所以不會是18.
代碼定義完成後,作用域就已經生成。以後調用時會通過其定義域關系向上查找(不管這個函數名是在哪裏被調用,只要一執行,它還是會回來它定義的地方向上去查找。)。
匿名函數:
普通函數:
def calc( x,y):
return x*y
匿名函數: lambda x,y: x*y #聲明一個匿名函數 (把多行語句變成一行)
調用:
func = lambda x,y: x*y
func(3,8)
匿名函數最復雜的也只能進行三元運算。
匿名函數通常跟其他的方法搭配使用,作用主要是節省代碼量、如:
# 要求: 使range(10)裏面的數各自跟自己相乘 data = list(range(10)) print(list(map(lambda x:x*x,data))) # 輸出結果: # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # map的用法: map(func, *iterables) --> map object # 就是把iterables中的每一個值都進行一下前面的函數。 # list(map())的作用是讓map的結果變成列表的樣子 # iterables有:list,str,tuple,dict,file,xrange等
高階函數:
變量可以指向函數,函數的參數能夠接收變量,一個函數可以接收另一個函數作為參數,這種函數就叫高階函數。
另外,一個函數return了另外一個函數,這個也是高階函數,如:
def func(x,y): return abs,x,y res = func(3,-10) # func也是高階函數 # abs是求絕對值的函數,用法:abs( 數字) # 函數返回多個值的時候,是以元祖形式返回的
總結:
只需滿足以下一個條件即為高階函數:
1. 接收一個或多個函數作為輸入
2. return返回另一個函數
遞歸函數:
如果一個函數在其內部調用了它自己,這樣的函數就是遞歸函數。 如:讓10除以2,直到為0.
a= 10 def calc(n): n = int(n/2) print(n) if n >0: calc(n) #在函數內部調用它自己,就會產生循環 calc(a) # 輸出結果: # 5 # 2 # 1 # 0 ## 而且,程序在結束退出的時候,是從內向外、一層一層逐漸結束的。 測試: a= 10 def calc(n): n = int(n/2) print(n) if n >0: #這一步的代碼運行分析:第1次print的n是5,由於5>0,n直接進入calc(n),由於calc(n)調用了它自己,就沒有再走下面的print(‘程序退出測試:’,n)這一步,而是又返回上面去進行n=int(n/2)這幾步。n是2和1的時候也是同樣的道理。 calc(n) print(‘程序退出測試:‘,n) # 打印結果分析:最後一輪循環n的值是0,此時n==0不再進行calc(n),而是去運行下面的print(‘程序退出測試:’,n)這一步,此時最裏面的這一層循環結束;然而上一步n==1時,程序是直接進入了if語句進行了calc(n),並沒有進行下面的print語句,所以當最裏面的n==0這層程序走完之後,n==1也要走完這個print語句。同理,n==2和5時也要依次走這個print語句。
calc(a) # 輸出結果: # 5 # 2 # 1 # 0 # 程序退出測試: 0 # 程序退出測試: 1 # 程序退出測試: 2 # 程序退出測試: 5
遞歸函數返回值:
在遞歸函數的外面得到返回值是最外層的函數return回來的,想要得到遞歸函數的返回值,需要在遞歸函數內部每次調用時都要有return值,只有這樣最內層的return值才能通過一層層的return返回到最外層。它的書寫方式是:
if 條件成立:
return 調用自己
else:
return 最裏面的值
例如下面兩個例子:
例子1: 100除以2三次,函數外部得到返回值。 a = 100 def func(n,count): if count < 3: return func(n/2,count+1) else: return n result = func(a,0) print(result) # 輸出結果: # 12.5 例子2: 求3的階乘,函數外部得到返回值。 def f(n): if n > 1: return n*f(n-1) else: return n print(f(3)) # 輸出結果: # 6
下面用流程圖說明它們的返回值是怎麽得到的:
1. 3的階乘:
2. 100除以2三次:
python函數基礎:嵌套函數、作用域、匿名函數、遞歸函數