1. 程式人生 > >python函數基礎:嵌套函數、作用域、匿名函數、遞歸函數

python函數基礎:嵌套函數、作用域、匿名函數、遞歸函數

body nbsp 方式 匿名函數 遞歸 能夠 三元運算 多個 用法

嵌套函數:

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,但由於變量需要先定義後使用(定於放在使用前面),所以程序會報錯。例如情景3
age = 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函數基礎:嵌套函數、作用域、匿名函數、遞歸函數