Python函數(shù)定義、參數(shù)、返回值與作用域示例詳解
1 ~> 什么是函數(shù)?
1.1 函數(shù)的概念
我們編程中的函數(shù)其實(shí)和數(shù)學(xué)中的函數(shù)有一定的相似之處:
數(shù)學(xué)上的函數(shù),比如y=sinx,x取不同的值,y就會(huì)得到不同的結(jié)果
編程中的函數(shù),指的是 一段可以被重復(fù)使用的代碼片段。

1.2 代碼示例
1.2.1 代碼示例:求數(shù)列的和,不使用函數(shù)
# 1. 求 1 - 100 的和
sum = 0
for i in range(1, 101):
sum += i
print(sum)
# 2. 求 300 - 400 的和
sum = 0
for i in range(300, 401):
sum += i
print(sum)
# 3. 求 1 - 1000 的和
sum = 0
for i in range(1, 1001):
sum += i
print(sum)我們通過觀察可以發(fā)現(xiàn),這幾組代碼基本是相似的,只有一點(diǎn)點(diǎn)差異,可以把重復(fù)代碼提取出來,寫成一個(gè)函數(shù)。
實(shí)際開發(fā)中,復(fù)制粘貼是一種不太好的策略,實(shí)際開發(fā)的重復(fù)代碼可能存在幾十份甚至上百份。
一旦這個(gè)重復(fù)代碼需要被修改,那就得改幾十次,非常不便于維護(hù)。
1.2.2 代碼示例:求數(shù)列的和,使用函數(shù)
# 定義函數(shù)
def calcSum(beg, end):
sum = 0
for i in range(beg, end + 1):
sum += i
print(sum)
# 調(diào)用函數(shù)
sum(1, 100)
sum(300, 400)
sum(1, 1000)這里我們可以明顯看到——重復(fù)的代碼已經(jīng)被消除了。
1.3 最佳實(shí)踐:針對(duì)上面的示例
# 函數(shù)
# 函數(shù)是什么
# 三角函數(shù) sin、cos
# “隱射關(guān)系”
# 函數(shù):一段可以被反復(fù)使用的代碼 ctrl + c,ctrl + v
# 1、復(fù)制代碼,必須要非常仔細(xì)地進(jìn)行細(xì)節(jié)調(diào)整,尤其是在數(shù)據(jù)不同的情況下
# 2、一旦復(fù)制過的代碼需要調(diào)整,復(fù)制了幾份就得調(diào)整幾次(搞不清楚這個(gè)代碼究竟被復(fù)制了幾份了)
# 因此,盡量還是不要復(fù)制代碼,盡量做好代碼“復(fù)用”
# 其他邏輯都是一樣的,我們可以用函數(shù)的方式,達(dá)到復(fù)用代碼的效果
# 1、求1 - 100的和
thSum = 0
for i in range(1,101):
thSum += i
print(thSum)
# 2、求300 - 400的和
thSum = 0 # 由于前面已經(jīng)有了thSum了,這里相當(dāng)于賦值操作
for i in range(300,401):
thSum += i
print(thSum)
#3、求1 - 1000的和
thSum = 0
for i in range(1,1001):
thSum += i
print(thSum)
# 在新的文件里面實(shí)現(xiàn)這個(gè)函數(shù)
我們創(chuàng)建一個(gè)新的文件,并且在新的文件里面實(shí)現(xiàn)這個(gè)函數(shù)——
# 使用函數(shù)的方式來解決剛才的問題:
# 有什么地方要改也只要改一次就好了
# 定義一個(gè)求和函數(shù)
def calcSum(beg,end):
theSum = 0
for i in range(beg,end + 1):
theSum += i
print(theSum) # 跟for同一級(jí)縮進(jìn)
# 調(diào)用函數(shù)
# 求1 - 100的和
calcSum(1,100)
#求300 - 400的和
calcSum(300,400)
# 求1 - 1000的和
calcSum(1,1000)

2 ~> 語法格式
2.1 創(chuàng)建函數(shù) / 定義函數(shù)
def 函數(shù)名(形參列表):
函數(shù)體
return 返回值
2.2 調(diào)用函數(shù) / 使用函數(shù)
函數(shù)名(實(shí)參列表) // 不考慮返回值 返回值 = 函數(shù)名(實(shí)參列表) // 考慮返回值

2.2.1 函數(shù)定義并不會(huì)執(zhí)行函數(shù)體內(nèi)容,必須要調(diào)用才會(huì)執(zhí)行:調(diào)用幾次就會(huì)執(zhí)行幾次
def test1():
print('hello')
# 如果光是定義函數(shù), 而不調(diào)用, 則不會(huì)執(zhí)行.
2.2.2 函數(shù)必須先定義,再使用
test3() # 還沒有執(zhí)行到定義, 就先執(zhí)行調(diào)用了, 此時(shí)就會(huì)報(bào)錯(cuò).
def test3():
print('hello')
報(bào)錯(cuò)——

2.2.3 類比
在霓虹國的熱血?jiǎng)勇?,角色釋放技能之前,需要大喊招式的名字,比?ldquo;草帽小子”蒙奇·D·路飛每次使用惡魔果實(shí)力量時(shí)就會(huì)喊出“橡膠橡膠!XXX”,像角色先喊招式再放大招這個(gè)行為就可以理解為 “先定義, 再使用”。
2.3 最佳實(shí)踐
# 函數(shù)的定義和調(diào)用
# 返回值 = 函數(shù)名(實(shí)參列表)
# 先定義一個(gè)函數(shù)
# 如果只是定義,而不去調(diào)用,則函數(shù)體里面的代碼就不會(huì)執(zhí)行!
def test():
print('Alice')
print('Alice')
print('Alice')
# 函數(shù)調(diào)用才會(huì)真正執(zhí)行函數(shù)體里面的代碼
# 函數(shù)經(jīng)過一次定義之后,可以被調(diào)用多次!
test()
test()
test()
test()
test()
# 運(yùn)行結(jié)果:
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Alice
# Python中要求,函數(shù)定義寫在前面,函數(shù)調(diào)用寫在后面-->先定義,后調(diào)用
2.4 代碼警告的處理

# 代碼警告的處理
# 警告-->提示你的代碼可能存在問題,但是并不影響程序編譯執(zhí)行(比較嚴(yán)重)
# 錯(cuò)誤-->代碼中實(shí)打?qū)嵉挠袉栴}?。ǚ浅?yán)重!影響到代碼了)
# 這兩個(gè)事情嚴(yán)重程度是完全不同的!
# 定義一個(gè)求和函數(shù)
# 點(diǎn)擊[忽略這個(gè)“錯(cuò)誤(遠(yuǎn)不到錯(cuò)誤這個(gè)級(jí)別,只能說是警告)”]
def calcSum(beg, end): # 報(bào)了警告
theSum = 0 # 剛才是函數(shù)名,這里是變量名,我們同樣選擇[忽略]
for i in range(beg,end + 1):
theSum += i
print(theSum) # 跟for同一級(jí)縮進(jìn)
# 調(diào)用函數(shù)
# 求1 - 100的和
calcSum(1, 100)
#求300 - 400的和
calcSum(300, 400)
# 求1 - 1000的和
calcSum(1, 1000)
# 文件末尾建議加上空行
# PEP8,這是Pyhton里面一套非常流行的編程規(guī)范,也就是寫代碼中的一些“軟性要求”
# 未來咱們在公司里面究竟是使用啥樣的規(guī)范?不確定,只要代碼風(fēng)格干凈整潔即可。
3 ~> 函數(shù)參數(shù):實(shí)參、形參
3.1 概念
在函數(shù)定義的時(shí)候,可以在()中指定“形式參數(shù)”(簡稱形參),然后在調(diào)用的時(shí)候,由調(diào)用者把“實(shí)際參數(shù)’(簡稱實(shí)參)傳遞進(jìn)去。
這樣就可以做到:一份函數(shù),針對(duì)不同的數(shù)據(jù)進(jìn)行計(jì)算處理。
3.2 示例
我們結(jié)合一下前面的代碼示例——
def calcSum(beg, end):
sum = 0
for i in range(beg, end + 1):
sum += i
print(sum)
sum(1, 100)
sum(300, 400)
sum(1, 1000)
上面的代碼中,beg,end就是函數(shù)的形參1,100 / 300,400就是函數(shù)的實(shí)參。
在執(zhí)行
sum(1,100)的時(shí)候,就相當(dāng)于beg = 1,end = 100,然后在函數(shù)內(nèi)部就可以針對(duì)1 - 100進(jìn)行運(yùn)算。
在執(zhí)行sum(300,400)的時(shí)候,就相當(dāng)于beg = 300,end = 400,然后在函數(shù)內(nèi)部就可以針對(duì)300 - 400 進(jìn)行運(yùn)算。
實(shí)參和形參之間的關(guān)系,就像簽合同一樣。

甲方、乙方這就相當(dāng)于形參,艾莉絲、魯?shù)蠟跛咕褪菍?shí)參。
def 簽合同(甲方, 乙方):
合同內(nèi)容....
簽合同('艾莉絲', '魯?shù)蠟跛?)
簽合同('艾莉絲', '希露菲')
簽合同('艾莉絲', '洛琪希')3.3 注意
一個(gè)函數(shù)可以有一個(gè)形參,也可以有多個(gè)形參,也可以沒有形參。
一個(gè)函數(shù)的形參有幾個(gè),那么傳遞實(shí)參的時(shí)候也得傳幾個(gè),保證個(gè)數(shù)要匹配。
def test(a, b, c):
print(a, b, c)
test(10)![]()
和C++/Java不同,Python是動(dòng)態(tài)類型的編程語言,函數(shù)的形參不必指定參數(shù)類型.換句話說,一個(gè)函數(shù)可以支持多種不同類型的參數(shù)。
def test(a):
print(a)
test(10)
test('hello')
test(True)
3.4 最佳實(shí)踐
3.4.1 實(shí)參
# 函數(shù)的參數(shù)(1)
# 形參和實(shí)參
def test(a,b,c):
print(a,b,c)
test(10) # 函數(shù)形參數(shù)量要和形參數(shù)量要匹配
3.4.2 形參
# 函數(shù)的參數(shù)(2)
# 形參和實(shí)參
# def test(a):
# print(a)
#
# test(10)
# test('hello')
# test(True)
def add(a,b):
return a + b
print(add(10,20)) # 整型相加
print(add(1.5,2.5)) # 浮點(diǎn)型相加
print(add('hello','world')) # 字符串相加
print(add(10,'hello')) # 報(bào)錯(cuò),不能相加
4 ~> 函數(shù)返回值
4.1 概念
函數(shù)的參數(shù)可以視為是函數(shù)的“輸入”,則函數(shù)的返回值,就可以視為是函數(shù)的“輸出”。
此處的“輸入”,“輸出”是更廣義的輸入輸出,不是單純指通過控制臺(tái)輸入輸出。
我們可以把函數(shù)想象成一個(gè)“工廠",工廠需要買入原材料,進(jìn)行加工,并生產(chǎn)出產(chǎn)品。
函數(shù)的參數(shù)就是原材料,函數(shù)的返回值就是生產(chǎn)出的產(chǎn)品。
4.2 示例
4.2.1 示例代碼
def calcSum(beg, end):
sum = 0
for i in range(beg, end + 1):
sum += i
print(sum)
calc(1, 100)
這段代碼可以可以轉(zhuǎn)換成——
def calcSum(beg, end):
sum = 0
for i in range(beg, end + 1):
sum += i
return sum
result = calcSum(1, 100)
print(result)這兩個(gè)代碼的區(qū)別就在于,前者直接在函數(shù)內(nèi)部進(jìn)行了打印,后者則使用 return 語句把結(jié)果返回給函數(shù)調(diào)用者,再由調(diào)用者負(fù)責(zé)打印。
我們一般傾向于第二種寫法。
實(shí)際開發(fā)中我們的一個(gè)通常的編程原則,是“邏輯和用戶交互分離”而第一種寫法的函數(shù)中,既包含了計(jì)算邏輯,又包含了和用戶交互(打印到控制臺(tái)上),這種寫法是不太好的,如果后續(xù)我們需要的是把計(jì)算結(jié)果保存到文件中,或者通過網(wǎng)絡(luò)發(fā)送,或者展示到圖形化界面里,那么第一種寫法的函數(shù),就難以勝任了。
而第二種寫法則專注于做計(jì)算邏輯,不負(fù)責(zé)和用戶交互,那么就很容易把這個(gè)邏輯搭配不同的用戶交互代碼,來實(shí)現(xiàn)不同的效果。


4.2.2 一個(gè)函數(shù)中可以有多個(gè)return語句
# 判定是否是奇數(shù)
def isOdd(num):
if num % 2 == 0:
return False
else:
return True
result = isOdd(10)
print(result)
4.2.3 執(zhí)行到return語句,函數(shù)就會(huì)立即執(zhí)行結(jié)束,回到調(diào)用位置
# 判定是否是奇數(shù)
def isOdd(num):
if num % 2 == 0:
return False
return True
result = isOdd(10)
print(result)如果num是偶數(shù),則進(jìn)入 if 之后,就會(huì)觸發(fā)return False,也就不會(huì)繼續(xù)執(zhí)行return True。

4.2.4 一個(gè)函數(shù)是可以一次返回多個(gè)返回值的,使用來分割多個(gè)返回值

4.2.5 一個(gè)函數(shù)是可以一次返回多個(gè)返回值的,使用_來分割多個(gè)返回值
def getPoint():
x = 10
y = 20
return x, y
_, b = getPoint()4.3 最佳實(shí)踐
# 函數(shù)的返回值(1)
# 求beg,end這個(gè)范圍的整數(shù)之和
def calSum(beg, end):
theSum = 0
for i in range(beg,end + 1):
theSum += i
return theSum
result = calSum(1,100)
print(result)
# 函數(shù)的返回值(2)
# 這種情況下,不算是有多個(gè) return 語句
# def test1():
# return 1
# return 2
# 一般多個(gè) return 語句是搭配分支/循環(huán)語句的
# def isOdd(num):
# """
# 用來判定 num 是不是奇數(shù),如果是奇數(shù)就返回 True,不是就返回 False
# :param num:要判定的整數(shù)
# :return:返回 True False 表示是不是奇數(shù)
# """
# # 第一種寫法
# # if num % 2 == 0:
# # return True
# # else:
# # return False
#
# # 第二種寫法
# if num % 2 == 0:
# return False
# return True
#
# print(isOdd(10))
# print(isOdd(19))
# 寫一個(gè)函數(shù),返回平面上的一個(gè)點(diǎn)
# 橫坐標(biāo),縱坐標(biāo)
def getPoint():
x = 10
y = 20
return x,y
a,b = getPoint()
print(a,b)
5 ~> 變量作用域
5.1 示例
觀察下面的代碼——
def getPoint():
x = 10
y = 20
return x, y
x, y = getPoint()在這個(gè)代碼中,函數(shù)內(nèi)部存在x,y,函數(shù)外部也有x,y,但是這兩組x、y不是相同的變量,而只是恰好有一樣的名字。
5.2 理論

5.2.1 變量只能在所在的函數(shù)內(nèi)部生效
在函數(shù)getPoint內(nèi)部定義的x、y只是在函數(shù)內(nèi)部生效,一旦出了函數(shù)的范圍,這兩個(gè)變量就不再生效。
def getPoint():
x = 10
y = 20
return x, y
getPoint()
print(x, y)
5.2.2 在不同的作用域中,允許存在同名的變量
雖然 名字相同,實(shí)際上是不同的變量。
x = 20
def test():
x = 10
print(f'函數(shù)內(nèi)部 x = {x}')
test()
print(f'函數(shù)外部 x = {x}')
注意:
在函數(shù)內(nèi)部的變量,也稱為“局部變量”;
不在任何函數(shù)內(nèi)部的變量,也稱為“全局變量”。
5.2.3 如果函數(shù)內(nèi)部嘗試訪問的變量在局部不存在,就會(huì)嘗試去全局作用域中查找
x = 20
def test():
print(f'x = {x}')
test()
5.2.4 如果是想在函數(shù)內(nèi)部,修改全局變量的值,需要使用global關(guān)鍵字聲明
x = 20
def test():
global x
x = 10
print(f'函數(shù)內(nèi)部 x = {x}')
test()
print(f'函數(shù)外部 x = {x}')
如果此處沒有global,則函數(shù)內(nèi)部的x = 10就會(huì)被視為是創(chuàng)建一個(gè)局部變量x,這樣就和全局變量x不相關(guān)了。

5.2.5 if / while / for等語句塊不會(huì)影響到變量作用域
換而言之,在if / while / for中定義的變量,在語句外面也可以正常使用。
for i in range(1, 10):
print(f'函數(shù)內(nèi)部 i = {i}')
print(f'函數(shù)外部 i = {i}')5.3 最佳實(shí)踐
# 變量的作用域
# 函數(shù)里面的x,y和函數(shù)外面的x,y是同一組變量嗎?
# 不同的變量,只不過名字恰好相同!
# def getPoint():
# x = 10
# y = 20
# return x,y
# 函數(shù)內(nèi)部的變量名,只能在函數(shù)內(nèi)部生效,出了函數(shù),就無效了!
# x,y = getPoint()
# print(x,y)
# 變量的作用域!
# 一個(gè)變量名的生效范圍是一定的!只在一個(gè)固定的區(qū)域內(nèi)生效
# def getPoint():
# x = 10
# y = 20
# return x,y
#
# getPoint()
# print(x,y)
# 函數(shù)內(nèi)部的x,y不生效-->NameError: name 'x' is not defined
# 函數(shù)內(nèi)部和函數(shù)外部是可以使用同名的變量的,雖然變量名相同,但是是不同的變量!
# 全局變量和局部變量
# 例子:
# x = 10
#
# def test():
# x = 20
# print(f"函數(shù)內(nèi)部:{x}")
#
# test()
# print(f"函數(shù)外部:{x}")
# 函數(shù)里,也是可以使用全局變量的!
# 例子:在函數(shù)里嘗試讀取全局變量是可以的!
# x = 10
#
# def test():
# print(f"x = {x}")
#
# test()
# x = 10
#
# def test():
# print(f"函數(shù)內(nèi)部:{x}")
#
# test()
# print(f"函數(shù)外部:{x}")
# 在函數(shù)中嘗試訪問某個(gè)變量的時(shí)候,會(huì)先嘗試在局部變量中查找,如果找到,就直接訪問;
# 如果沒找到,就會(huì)往上一級(jí)作用域中進(jìn)行查找-->test再往上一級(jí)作用域,就是全局了
# 使用這個(gè)函數(shù),把全局變量 x 給改成 20!
# x = 10
#
# def test():
# x = 20 # 這個(gè)x被當(dāng)成函數(shù)內(nèi)部的局部變量了
#
# test()
# print(f"x = {x}")
# Python中的關(guān)鍵字:global
# x = 10
#
# def test():
# # 聲明,變成針對(duì)全局變量來進(jìn)行的了
# global x
# x = 20 # 這個(gè)x被當(dāng)成函數(shù)內(nèi)部的局部變量了
# # 由于修改全局變量的操作和創(chuàng)建變量的語法是一模一樣的,所以Python把它當(dāng)做是局部變量了
# # (所以要加上 global 進(jìn)行顯式聲明)
#
# test()
# print(f"x = {x}")
# 沒有 global ,此時(shí)就會(huì)把x = 20當(dāng)做是在函數(shù)內(nèi)部創(chuàng)建了一個(gè)局部變量 x
# 而實(shí)際上是要修改全局變量 x ,為了讓函數(shù)里面知道 x 是個(gè)全局變量,就使用 global 關(guān)鍵字先聲明一下
# if else,while,for這些關(guān)鍵字也會(huì)引入“代碼塊”,但是這些代碼塊不會(huì)對(duì)變量的作用域產(chǎn)生影響!!
# 在上述語句代碼塊內(nèi)部定義的變量,可以在外面被訪問!
# for i in range(1,11):
# print(i)
#
# print('------------------------')
# print(i)
# 輸出:
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10
# ------------------------
# 10
if True:
x = 10
print(x)
6 ~> 函數(shù)執(zhí)行過程
6.1 概念
調(diào)用函數(shù)才會(huì)執(zhí)行函數(shù)體代碼,不調(diào)用則不會(huì)執(zhí)行。
函數(shù)體執(zhí)行結(jié)束(或者遇到return語句)則回到函數(shù)調(diào)用位置,繼續(xù)往下執(zhí)行。

6.2 示例
def test():
print("執(zhí)行函數(shù)內(nèi)部代碼")
print("執(zhí)行函數(shù)內(nèi)部代碼")
print("執(zhí)行函數(shù)內(nèi)部代碼")
print("1111")
test()
print("2222")
test()
print("3333")
6.3 打斷點(diǎn)
6.3.1 調(diào)試器觀察函數(shù)執(zhí)行過程
這個(gè)過程還可以使用PyCharm自帶的調(diào)試器來觀察。

點(diǎn)擊行號(hào)右側(cè)的空白,可以在代碼中插入 斷點(diǎn)。
右鍵,Debug,可以按照調(diào)試模式執(zhí)行代碼,每次執(zhí)行到斷點(diǎn),程序都會(huì)暫停下來。
使用StepInto(F7) 功能可以逐行執(zhí)行代碼。
6.3.2 舉個(gè)例子

6.4 最佳實(shí)踐
# 函數(shù)的執(zhí)行過程
def test():
print('執(zhí)行函數(shù)體代碼')
print('執(zhí)行函數(shù)體代碼')
print('執(zhí)行函數(shù)體代碼')
print("111111")
test()
print("222222")
test()
print("333333")
test()
print("444444")
test()
print("555555")
test()
# 還可以使用PyCharm的調(diào)試器,也能觀察函數(shù)執(zhí)行的過程
# 調(diào)試執(zhí)行相比于正常的區(qū)別:就是可以隨時(shí)停下來,方便程序員觀察程序的中間過程
# 調(diào)試:F7,step into

7 ~> 鏈?zhǔn)秸{(diào)用和嵌套調(diào)用
7.1 鏈?zhǔn)秸{(diào)用
7.1.1 示例
# 判定是否是奇數(shù)
def isOdd(num):
if num % 2 == 0:
return False
else:
return True
result = isOdd(10)
print(result)
實(shí)際上也可以簡化一下,寫作——
print(isOdd(10))
7.1.2 概念
把一個(gè)函數(shù)的返回值,作為另一個(gè)函數(shù)的參數(shù),這種操作稱為 鏈?zhǔn)秸{(diào)用。
這是一種比較常見的寫法。

7.1.3 最佳實(shí)踐
# 函數(shù)的鏈?zhǔn)秸{(diào)用和嵌套調(diào)用(1)
# 鏈?zhǔn)秸{(diào)用
def isOdd(num):
if num % 2 == 0:
return False
return True
def add(x,y):
return x + y
# result = isOdd(10)
# print(result)
print(isOdd(add(5,5)))
7.2 嵌套調(diào)用
7.2.1 概念
函數(shù)內(nèi)部還可以調(diào)用其他的函數(shù),這個(gè)動(dòng)作稱為 “嵌套調(diào)用”。
test函數(shù)內(nèi)部調(diào)用了print函數(shù),這里就屬于嵌套調(diào)用。
7.2.2 一個(gè)函數(shù)里面可以嵌套調(diào)用任意多個(gè)函數(shù)
函數(shù)嵌套的過程是非常靈活的。
def a():
print("函數(shù) a")
def b():
print("函數(shù) b")
a()
def c():
print("函數(shù) c")
b()
def d():
print("函數(shù) d")
c()
d()

如果把代碼稍微調(diào)整,打印結(jié)果則可能發(fā)生很大變化。
def a():
print("函數(shù) a")
def b():
a()
print("函數(shù) b")
def c():
b()
print("函數(shù) c")
def d():
c()
print("函數(shù) d")
d()

注意體會(huì)上述代碼的執(zhí)行順序,我們可以通過畫圖的方式來理解。
函數(shù)之間的調(diào)用關(guān)系,在Python中會(huì)使用一個(gè)特定的數(shù)據(jù)結(jié)構(gòu)來表示,稱為 函數(shù)調(diào)用棧。每次函數(shù)調(diào)用,都會(huì)在調(diào)用棧里新增一個(gè)元素,稱為 棧幀。

可以通過PyCharm調(diào)試器看到函數(shù)調(diào)用棧和棧幀。
在調(diào)試狀態(tài)下,PyCharm左下角一般就會(huì)顯示出函數(shù)調(diào)用棧。

7.2.3 每個(gè)函數(shù)的局部變量,都包含在自己的棧幀中
def a():
num1 = 10
print("函數(shù) a")
def b():
num2 = 20
a()
print("函數(shù) b")
def c():
num3 = 30
b()
print("函數(shù) c")
def d():
num4 = 40
c()
print("函數(shù) d")
d()
選擇不同的棧幀,就可以看到各自棧幀中的局部變量。
思考: 上述代碼,a,b,c,d函數(shù)中的局部變量名各不相同.如果變量名是相同的,比如都是 num,那么
這四個(gè)函數(shù)中的num是屬于同一個(gè)變量,還是不同變量呢?
7.2.4 最佳實(shí)踐
# 函數(shù)的鏈?zhǔn)秸{(diào)用和嵌套調(diào)用(2)
# 嵌套調(diào)用
# def test():
# print("Alice")
#
# test()
# 嵌套調(diào)用層次可以有很多層
# def a():
# print('函數(shù) a')
#
# def b():
# print('函數(shù) b')
# a()
#
# def c():
# print('函數(shù) c')
# b()
#
# def d():
# print('函數(shù) d')
# c()
#
# d()
# # 運(yùn)行結(jié)果
# 函數(shù) d
# 函數(shù) c
# 函數(shù) b
# 函數(shù) a
# 代碼順序稍作調(diào)整,打印順序就會(huì)變化
def a():
print('函數(shù) a')
def b():
a()
print('函數(shù) b')
def c():
b()
print('函數(shù) c')
def d():
c()
print('函數(shù) d')
d()
# # 運(yùn)行結(jié)果
# 函數(shù) a
# 函數(shù) b
# 函數(shù) c
# 函數(shù) d
8 ~> 局部變量和函數(shù)棧幀
8.1 概念

8.2 最佳實(shí)踐
# 局部變量和函數(shù)棧幀
# 這幾個(gè)變量雖然同名,但是是不同變量,屬于不同的函數(shù)作用域
# 每個(gè)變量也是保存在各自的棧幀中的(每個(gè)棧幀也是保存在內(nèi)存中)
# 變量本質(zhì)是一塊內(nèi)存空間
def a():
num = 10
print('函數(shù) a')
def b():
num = 20
a()
print('函數(shù) b')
def c():
num = 30
b()
print('函數(shù) c')
def d():
num = 40
c()
print('函數(shù) d')
d()

9 ~> 函數(shù)遞歸
9.1 函數(shù)遞歸的概念
遞歸是嵌套調(diào)用中的一種特殊情況:即一個(gè)函數(shù)嵌套調(diào)用自己。

9.2 示例:遞歸計(jì)算5!
def factor(n):
if n == 1:
return 1
return n * factor(n - 1)
result = factor(5)
print(result)上述代碼中,就屬于典型的遞歸操作。在 factor 函數(shù)內(nèi)部,又調(diào)用了 factor 自身。
注意:遞歸代碼務(wù)必要保證——
(1)存在遞歸結(jié)束條件:比如if n == 1就是結(jié)束條件,當(dāng)n為1的時(shí)候,遞歸就結(jié)束了;
(2)每次遞歸的時(shí)候,要保證函數(shù)的實(shí)參是逐漸逼近結(jié)束條件的。
如果上述條件不能滿足,就會(huì)出現(xiàn)“無限遞歸”,這是一種典型的代碼錯(cuò)誤。
def factor(n):
return n * factor(n - 1)
result = factor(5)
print(result)![]()
正如前面所描述的那樣,函數(shù)調(diào)用時(shí)會(huì)在函數(shù)調(diào)用棧中記錄每一層函數(shù)調(diào)用的信息。
但是函數(shù)調(diào)用棧的空間不是無限大的,如果調(diào)用層數(shù)太多,就會(huì)超出棧的最大范圍,導(dǎo)致出現(xiàn)問題。
9.3 最佳實(shí)踐
# 函數(shù)遞歸
# 寫一個(gè)函數(shù),來求 n 的階乘(n 是正整數(shù))
# 用循環(huán)的方式來寫
# def factor(n):
# result = 1
# for i in range(1,n + 1):
# result *= i
# return result
#
# print(factor(5))
# 用遞歸的方式來寫
# n! => n * (n - 1)
# 1! => 1
def factor(n):
if n == 1:
return 1
return n * factor(n - 1)
print(factor(5))
9.4 遞歸的優(yōu)缺點(diǎn)
9.4.1 遞歸的優(yōu)點(diǎn)
(1)遞歸類似于“數(shù)學(xué)歸納法”,明確初始條件,和遞推公式,就可以解決一系列的問題;
(2)遞歸代碼往往代碼量非常少。
9.4.2 遞歸的缺點(diǎn)
(1)遞歸代碼往往難以理解,很容易超出掌控范圍;
(2)遞歸代碼容易出現(xiàn)棧溢出的情況;
(3)遞歸代碼往往可以轉(zhuǎn)換成等價(jià)的循環(huán)代碼,并且通常來說循環(huán)版本的代碼執(zhí)行效率要略高于遞歸版本。
9.4.3 基于遞歸的優(yōu)缺點(diǎn),使用遞歸的結(jié)論
在我們實(shí)際開發(fā)的時(shí)候,使用遞歸要慎重!
10 ~> 參數(shù)默認(rèn)值
10.1 概念
Python中的函數(shù),可以給形參指定默認(rèn)值。
帶有默認(rèn)值的參數(shù),可以在調(diào)用的時(shí)候不傳參。
10.2 最佳實(shí)踐
10.2.1 代碼示例:計(jì)算兩個(gè)數(shù)字的和
def add(x, y, debug=False):
if debug:
print(f'調(diào)試信息: x={x}, y={y}')
return x + y
print(add(10, 20))
print(add(10, 20, True))此處debug=False即為參數(shù)默認(rèn)值。當(dāng)我們不指定第三個(gè)參數(shù)的時(shí)候,默認(rèn)debug的取值即為False。
10.2.2 帶有默認(rèn)值的參數(shù)需要放到?jīng)]有默認(rèn)值的參數(shù)的后面
def add(x, debug=False, y):
if debug:
print(f'調(diào)試信息: x={x}, y={y}')
return x + y
print(add(10, 20))帶有默認(rèn)值的參數(shù)如果沒有放到?jīng)]有默認(rèn)值的參數(shù)的后面就會(huì)報(bào)錯(cuò)——

10.2.3 實(shí)踐
# 函數(shù)形參的默認(rèn)值
# 通過這樣的默認(rèn)值,就可以讓函數(shù)的設(shè)計(jì)更靈活!
# debug:形參的默認(rèn)值
# 帶有默認(rèn)值的形參就可以在調(diào)用函數(shù)的時(shí)候,不必傳參
# 參數(shù)越多會(huì)提高使用者的成本
def add(x ,y ,debug=False):
if debug:
print(f'x = {x},y = {y}')
return x + y
# result = add(10,20) # 不開啟調(diào)試信息的情況,只傳了兩個(gè)實(shí)參
result = add(10,20,True)
# result = add(10,20,False)
print(result)
# 像默認(rèn)值這樣的語法,在編程界是存在爭議的!
# C++也支持形參默認(rèn)參數(shù),Java就不支持,但是Python還是引入默認(rèn)參數(shù)的
# 帶有默認(rèn)值的形參得在形參列表的后面,而不能在前面 / 中間!
# 多個(gè)帶有默認(rèn)值的形參,這些都得在形參列表的后面
# 報(bào)錯(cuò):SyntaxError: parameter without a default follows parameter with a default11 ~> 關(guān)鍵字參數(shù)
11.1 概念
在調(diào)用函數(shù)的時(shí)候,需要給函數(shù)指定實(shí)參,一般默認(rèn)情況下是按照形參的順序,來依次傳遞實(shí)參的,但是我們也可以通過 關(guān)鍵字參數(shù),來調(diào)整這里的傳參順序,顯式指定當(dāng)前實(shí)參傳遞給哪個(gè)形參。

11.2 示例
def test(x, y):
print(f'x = {x}')
print(f'y = {y}')
test(x=10, y=20)
test(y=100, x=200)運(yùn)行結(jié)果如下所示——

11.3 最佳實(shí)踐
# 函數(shù)的關(guān)鍵字參數(shù)
# 按照先后順序來傳參——這種傳參風(fēng)格,稱為“位置參數(shù)” 這是各個(gè)編程語言中最普遍的方式!
# 關(guān)鍵字傳參:按照形參的名字來進(jìn)行傳參!
def test(x,y):
print(f'x = {x}')
print(f'y = {y}')
test(x=10,y=20) # 非常明顯地告訴程序員:你的參數(shù)要傳給誰!另外可以無視形參和實(shí)參的順序!
test(y=100,x=200)
# 運(yùn)行結(jié)果
# x = 10
# y = 20
# x = 200
# y = 100
# 位置參數(shù)和關(guān)鍵字參數(shù)還能混著用,只不過混著用的時(shí)候要求位置參數(shù)在前。
# 關(guān)鍵字參數(shù)在后
# 關(guān)鍵字參數(shù)一般也就是搭配默認(rèn)參數(shù)來使用的
# 一個(gè)函數(shù),可以提供很多的參數(shù),來實(shí)現(xiàn)對(duì)這個(gè)函數(shù)的內(nèi)部功能做出一些調(diào)整設(shè)定
# 為了降低調(diào)用者的使用成本,就可以把大部分參數(shù)設(shè)定出默認(rèn)值
# 當(dāng)調(diào)用者需要調(diào)整其中的一部分參數(shù)的時(shí)候,就可以搭配關(guān)鍵字參數(shù)來進(jìn)行操作(在Python的文件操作部分會(huì)演示,這里不展開)
12 ~> Python基礎(chǔ)語法:函數(shù)部分小結(jié)
函數(shù)是編程語言中的一個(gè)核心語法機(jī)制。Python中的函數(shù)和大部分編程語言中的函數(shù)功能都是基本類似的。
我們當(dāng)下最關(guān)鍵要理解的主要就是三個(gè)點(diǎn):
函數(shù)的定義
函數(shù)的調(diào)用
函數(shù)的參數(shù)傳遞
在后續(xù)的編程中,我們會(huì)廣泛的使用到函數(shù),uu們要再反復(fù)加深對(duì)于函數(shù)的理解哦。
# 函數(shù)部分小結(jié) # 函數(shù)的定義 # 函數(shù)的調(diào)用 # 函數(shù)的參數(shù)傳遞過程 # 函數(shù)的執(zhí)行流程: # (1)進(jìn)去,好進(jìn) # (2)出來,不好出
結(jié)尾
到此這篇關(guān)于Python函數(shù)定義、參數(shù)、返回值與作用域的文章就介紹到這了,更多相關(guān)Python函數(shù)詳解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python實(shí)現(xiàn)在多維數(shù)組中挑選符合條件的全部元素
今天小編就為大家分享一篇python實(shí)現(xiàn)在多維數(shù)組中挑選符合條件的全部元素,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11
關(guān)于python中readlines函數(shù)的參數(shù)hint的相關(guān)知識(shí)總結(jié)
今天給大家?guī)淼氖顷P(guān)于Python函數(shù)的相關(guān)知識(shí),文章圍繞著python中readlines函數(shù)的參數(shù)hint展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
python安裝/卸載模塊方法步驟詳解(附詳細(xì)圖解)
在日常工作中會(huì)需要安裝或者卸載Python模塊.于是我整理了一下,下面這篇文章主要給大家介紹了關(guān)于python安裝/卸載模塊的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
python 連接各類主流數(shù)據(jù)庫的實(shí)例代碼
下面小編就為大家分享一篇python 連接各類主流數(shù)據(jù)庫的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01
Python?Tkinter庫從入門到進(jìn)階使用教程
Tkinter是Python標(biāo)準(zhǔn)庫中內(nèi)置的圖形用戶界面(GUI)工具包,提供了創(chuàng)建窗口、按鈕、文本框等GUI元素的功能,本文將介紹Tkinter的基礎(chǔ)知識(shí),幫助大家快速入門2023-12-12

