文章目錄
1. 函數的返回值
1) 返回值的作用
將函數裏面的數據傳遞到函數外面
2) 初學者如何判斷?
初學者怎麼確定需不需要返回值:
看函數的功能完成後要不要產生新的數據
3) 怎麼確定返回值?
函數聲明時,函數體中,
return後面的值就是函數的返回值
若沒有return,函數返回None
寫法 | 說明 | 作用 |
---|---|---|
return | 關鍵字 只能寫到函數體裏 |
確定函數的返回值 結束函數 |
執行函數體的時候如果遇到return,函數直接結束,同時將return後面的值作爲返回值返回
def sum_int(num1: int, num2: int):
return num1 + num2
4) 獲取函數的返回值
獲取函數調用表達式的值即可
例:用 3) 中的函數
result = sum_int(5, 2) + 2
print(result) # 結果:9
注:函數調用表達式就是函數調用語句
普通數據能做的事函數調用表達式就能做
上例子中,sum_int(5, 2) 的返回值是7,所以在語句中,和7的作用一模一樣,可以直接進行運算
2. 完整的函數調用過程
day9中的函數調用過程沒有涉及到返回值,這裏完善一下
1) 執行過程
a. 回到函數聲明位置
b. 傳參 - 保證每個參數都有值
c. 執行函數體
d. 執行完函數體確定返回值
看執行完函數體的時候有沒有遇到return
如果遇到了return,後面的值就是返回值
沒有遇到就返回None
e. 回到函數調用的位置
(這個時候函數調用表達式的值纔是函數的返回值)
2) 內存變化
函數的調用過程是一個壓棧的過程
調用函數的時候系統會自動在棧區間爲這個函數申請一個專用的內存區域,專門用來保存在函數中聲明的變量和產生的數據
注:形參也是聲明在函數中的變量
當函數結束的時候,這個內存區域會自動釋放
銷燬前會將返回值扔出來
3. 全局變量和局部變量
1) 變量的作用域
即變量可以使用的範圍
2) 全局變量
python: 沒有聲明在函數中或者類中的變量都是全局變量
全局變量從聲明開始到文件結束任何地方都可以使用
for b in range(4):
c = 100
pass
print(b, c) # 結果是3 100 這裏b、c都是全局變量
3) 局部變量
聲明在函數中的變量就是局部變量
(形參也是局部變量)
作用域:從聲明開始到函數結束
def func2(aa):
pass
func2(100)
print(aa) # 報錯,NameError,aa沒有被定義
ps:python裏,函數中還能聲明函數
4) global和nonlocal
global和nonlocal這兩個關鍵字只能在函數體中使用
a. global
a = 100
def func4():
a = 200
print('函數中', a)
func4()
print('函數外', a)
# 結果:
# '函數中' 200
# '函數外' 100
出現上面這個現象的原因是:
a = 100 的這個a是全局變量
函數中,a = 200 的這個a是函數中的局部變量,是一個新的變量
函數結束時,值是200的局部變量a在內存裏被釋放
而原來的值是100的a還是原來的a
a = 100
def func4():
global a # 這個單獨佔一行!!!
a = 200
print('函數中', a)
func4()
print('函數外', a)
# 結果:
# '函數中' 200
# '函數外' 200
寫法 | 說明 |
---|---|
global 變量 變量 = … |
函數中,在變量賦值前, 在函數中聲明此變量爲全局變量 |
b. nonlocal
使用場景:
在局部的局部中,修改局部的值
def func5():
a = 100
def func6():
a = 200 # 這裏也不行
print(a)
func6()
print(a)
# 結果:200 100
在func6中,修改a的值也不行
因爲a=200的a是func6的局部變量
同global一樣,只是nonlocal在局部中使用
def func5():
a = 100
def func6():
nonlocal a
a = 200 # 這裏可以
print(a)
func6()
print(a)
func5()
# 結果:200 200
*但是nonlocal不能聲明,只能修改!!!
def func5():
a = 100
def func6():
nonlocal b # 這裏報錯
b = 200
print(a)
func6()
print(a)
寫法 | 說明 |
---|---|
nonlocal 變量 變量 = … |
作用: 在子函數中,修改母函數的局部變量的值 |
nonlocal幾乎不用,因爲函數中聲明函數已經很少見了,在這種情況下還有在子函數中修改母函數的局部變量,更罕見了
4. 匿名函數
1) 什麼是匿名函數?
沒有名字的函數
匿名函數還是函數,普通函數中,除了聲明的語法以外,其他常用語法基本都適用於匿名函數
注:不支持普通函數中形參的參數類型說明
2) 聲明匿名函數
lambda 參數列表:返回值
寫法 | 說明 |
---|---|
lanmbda | 關鍵字,固定寫法 |
參數列表 | 形參:參數1,參數2,… |
: | 固定寫法,不產生縮進 |
返回值 | 相當於普通函數的return語句 |
相當於:
def (參數列表):
return 返回值
隨堂練習:
用匿名函數實現兩個數求和
func1 = lambda num1, num2: num1 + num2 # 聲明
print(func1(10, 20)) # 結果:30
因爲匿名,所以沒法直接調用,這裏暫時用一個變量去接
隨堂練習:
寫一個匿名函數判斷指定的年是否是閏年
loop_year = lambda year: (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
5. 遞歸函數
1) 什麼是遞歸函數
在聲明函數時調用函數本身的函數
即在聲明的時候調用自己
def func1():
func1() # 報錯
因爲每次執行函數都會壓棧,無限壓棧內存怎麼都不夠
遞歸可以實現循環效果
原則上,除了死循環,其他的循環用遞歸都可以實現
遞歸比循環會消耗多的多的內存空間
2) 遞歸怎麼用
使用遞歸的套路:
a. 設置臨界值 - 循環結束的條件(保證函數在臨界值結束)
b. 找關係 - 找f(n)和f(n-1)的關係
c. 假設函數的功能已經實現,通過f(n-1)去實現f(n)的功能
栗子:寫一個遞歸函數,計算1+2+3+…+N
def sum_num(n: int):
# 找臨界值
if n == 1:
return 1
# 找關係
"""
f(n): 1+2+3+...+n
f(n-1): 1+2+3+...+n-1
f(n) = f(n-1) + n
"""
# 用f(n-1)實現f(n)的功能
return sum_num(n - 1) + n
n=5時的實現過程:
這裏的 yt_sum() 和上面的 sum_num() 一樣
隨堂練習:
寫一個遞歸函數,求斐波那契數列的第n個數
1,1,2,3,5,8,13,21…
def fibonacci(n: int):
# 找臨界值
if n == 1 or n == 2:
return 1
# 找關係
# f(n) = f(n - 1) + f(n - 2)
# 用f(n-1)實現f(n)的功能
return fibonacci(n - 1) + fibonacci(n - 2)
練習:
寫一個遞歸函數:
n = 4
*
**
***
****
自己做的:
def star(n: int):
if n == 1:
return '*'
return star(n - 1) + '\n' + '*' * n
老師答案:
def print_star(n):
if n == 1:
print('*')
return
print_star(n - 1)
print(n * '*')
作業
完善昨天的作業,嘗試寫出交互式學生管理系統
學生管理系統見day10的週末篇