函數(shù)主要有定義和調(diào)用兩個(gè)階段段只,在定義階段,解釋器只檢查語(yǔ)法臊诊,不會(huì)執(zhí)行代碼囱稽,解釋器默幫我們定義了一些內(nèi)置函數(shù),如常用的print()
,len()
等誊垢。
定義一個(gè)函數(shù):
def print_s():
print('*'*15)
print('hello'.center(15,'*'))
print('*'*15)
print_s()
函數(shù)一般的定義方式:
def function_name(arg1,arg2,arg3):
# 注釋
函數(shù)體
return 返回值
函數(shù)名一般是動(dòng)詞,定義的三種方式:
- 無(wú)參:應(yīng)用場(chǎng)景僅僅只是執(zhí)行一些操作,比如與用戶交互拜马,打印。
- 有參:需要根據(jù)外部傳進(jìn)來(lái)的參數(shù)沐绒,才能執(zhí)行相應(yīng)的邏輯俩莽,比如統(tǒng)計(jì)長(zhǎng)度,求最大最小值乔遮。
- 空函數(shù):設(shè)計(jì)代碼結(jié)構(gòu)
return
return: 函數(shù)內(nèi)部可以有多個(gè)return,但只能執(zhí)行一次扮超,函數(shù)就結(jié)束調(diào)用,并且會(huì)把return后的值作為函數(shù)執(zhí)行的結(jié)果返回蹋肮。
- return 的返回值沒(méi)有類型限制
- 如果函數(shù)中沒(méi)有return,則返回None,等同于return None. 如果只是執(zhí)行一系列的操作出刷,不需要結(jié)果則無(wú)需返回值。
- return 一個(gè)值: 返回該值
- return val1,val2,val3 :返回(val1,val2,val3)
函數(shù)調(diào)用的三種形式
1.語(yǔ)句形式括尸,語(yǔ)句直接調(diào)用:
foo()
2.表達(dá)式形式巷蚪,直接帶入進(jìn)行運(yùn)算:
3*len('python')
3.函數(shù)中,使用另一個(gè)函數(shù)(返回值)作為參數(shù):
max(max(1,2),3)
函數(shù)的參數(shù)
函數(shù)的參數(shù)分為形參和實(shí)參兩種:
- 實(shí)參:在調(diào)用函數(shù)時(shí)濒翻,括號(hào)內(nèi)的參數(shù)稱為實(shí)參屁柏,實(shí)參就是變量值
- 形參: 在調(diào)用階段變量值才會(huì)綁定形參(變量名),調(diào)用結(jié)束后有送,接觸綁定淌喻。
參數(shù)的分類:
- 位置參數(shù): 按照從左到右的順序依次定義的參數(shù)
- 位置形參: 必須被傳值,并且要不多不少
- 位置實(shí)參: 與形參按照位置一一對(duì)應(yīng)
- 關(guān)鍵字實(shí)參: 指的是按照name=value的形式雀摘,給指定的參數(shù)賦值裸删,并不一定需要按位置順序賦值。
提示:
* 位置實(shí)參必須在關(guān)鍵字實(shí)參的前面
* 一定不要對(duì)同一個(gè)形參傳多次值
默認(rèn)參數(shù)
默認(rèn)參數(shù)一般是形參阵赠,在定義階段就已經(jīng)為形參傳值涯塔,在賦值的時(shí)候可以使用默認(rèn)值,也可以單獨(dú)賦值清蚀。
def newuser(name,age,sex='male'):
print(name,age,sex)
newuser('tt',18)
newuser('yy',22,'female')
提示:
* 默認(rèn)參數(shù)必須放在位置參數(shù)之后
* 默認(rèn)參數(shù)值在定義階段賦值一次匕荸,而且僅一次。
* 默認(rèn)參數(shù)的值應(yīng)該定義成不可變類型枷邪。
可變長(zhǎng)參數(shù)
可變長(zhǎng)參數(shù)指的是多個(gè)實(shí)參的個(gè)數(shù)可以任意變化榛搔,實(shí)參分為位置實(shí)參和關(guān)鍵字實(shí)參兩種:
- 按照位置定義的實(shí)參溢出的情況使用:
*
def foo(x,y,*args):
print(x)
print(y)
print(args)
foo(1,2,3,4,5)
輸出的內(nèi)容為變量值和元組。
- 按照關(guān)鍵字定義的實(shí)參溢出的情況:
**
def foo(x,y,**kwargs):
print(x)
print(y)
print(kwargs)
foo(x=1,y=2,a=3,b=4,c=5)
輸出的內(nèi)容為變量值和列表。
在有些場(chǎng)景下践惑,為了后期代碼的維護(hù)和擴(kuò)展腹泌,會(huì)使用一個(gè)中間函數(shù)(wrapper())對(duì)函數(shù)參數(shù)進(jìn)行傳遞,可以接受任意長(zhǎng)度,任意形式的參數(shù),而不改變?cè)镜膮?shù)順序和屬性:
def foo(name,age,sex='male'):
print(name)
print(age)
print(sex)
def wrapper(*args,**kwargs):
print(args)
print(kwargs)
foo(*args,**kwargs)
提示:關(guān)鍵字實(shí)參一定要在位置實(shí)參的后面
命名關(guān)鍵字參數(shù)
在*
后面定義的 形參稱為命名關(guān)鍵字參數(shù)
尔觉,必須是以關(guān)鍵字實(shí)參的形式傳值凉袱。
def foo(name,age,*,sex): # * 后面的sex為命名關(guān)鍵字參數(shù),對(duì)其傳值需要指明關(guān)鍵字穷娱,否則會(huì)報(bào)錯(cuò)绑蔫。
print(name)
print(age)
print(sex)
foo('andy',22,sex='male') # sex必須以關(guān)鍵字形式傳值
參數(shù)的使用順序
如果將多個(gè)參數(shù)放在一個(gè)函數(shù)中,那么他們必須遵循以下順序規(guī)則:
- 位置形參
name
- 默認(rèn)參數(shù)
age=22
- 可變長(zhǎng)參數(shù)
*args
- 命名關(guān)鍵字參數(shù)(一般在
*
后)sex=male
- 多值關(guān)鍵字參數(shù)
**kwargs
函數(shù)對(duì)象
函數(shù)的定義類似與變量的定義泵额,可以當(dāng)作對(duì)象來(lái)賦值:
def foo():
print('from foo')
f=foo # 函數(shù)本身被當(dāng)作對(duì)象賦值
f() # 執(zhí)行 f()
可以當(dāng)作函數(shù)的參數(shù)傳入:
def foo():
print('from foo')
def wrapper(func):
print(func)
wrapper(foo)
可以當(dāng)作函數(shù)的返回:
def foo():
pass
def wrapper(func):
return func
res=wrapper(foo)
print(res)
可以當(dāng)作容器類型的元素:
def foo():
pass
cmd_dic={'func':foo}
print(cmd_dic)
cmd_dic['func']()
函數(shù)嵌套
在調(diào)用一個(gè)函數(shù)的過(guò)程中調(diào)用另一個(gè)函數(shù):
def foo1():
print('from foo1')
def foo():
print('from foo')
foo1()
foo()
函數(shù)的嵌套可以使代碼簡(jiǎn)潔,邏輯更加清晰携添。在函數(shù)內(nèi)部定義的定義的變量和函數(shù)只能在函數(shù)的內(nèi)部訪問(wèn)嫁盲。
名稱空間
名稱空間是存放名字和變量值綁定關(guān)系的區(qū)域。
分為內(nèi)置名稱空間烈掠,全局名稱空間羞秤,局部名稱空間。內(nèi)置名稱空間:在python 解釋器啟動(dòng)時(shí)產(chǎn)生左敌,存放一些python內(nèi)置的名字瘾蛋。
全局名稱空間: 在執(zhí)行文件時(shí)產(chǎn)生,存放文件級(jí)別定義的名字矫限,非內(nèi)置和非函數(shù)中定義的為全局名稱哺哼。
局部名稱空間:在執(zhí)行文件的過(guò)程中,如果調(diào)用了函數(shù)叼风,則會(huì)產(chǎn)生該函數(shù)局部名稱空間取董,用來(lái)存放該函數(shù)內(nèi)定義的名字,該名字在函數(shù)調(diào)用時(shí)生效无宿,在函數(shù)調(diào)用結(jié)束后失效茵汰。
時(shí)那個(gè)名稱空間的加載順序:
內(nèi)置名稱空間 > 全局名稱空間 > 局部名稱空間
名稱空間的查找順序:
在局部定義: 局部 > 全局 > 內(nèi)置
在全局定義: 全局 > 內(nèi)置
在執(zhí)行的當(dāng)前位置作為起始,一層一層往上找孽鸡。
作用域
分為全局作用域和局部作用域蹂午。
全局作用域:全局存活,全局有效
局部作用域:臨時(shí)存活彬碱,只在局部有效豆胸。
全局的局部其實(shí)也是全局本身。
對(duì)全局的不可變類型如果在函數(shù)內(nèi)部要進(jìn)行修改堡妒,需要添加global配乱。
對(duì)全局的可變類型進(jìn)行修改在函數(shù)內(nèi)部直接修改即可
x=1
def f():
global x # 全局的不可變類型需要添加global
x=2
l=[1,2,3]
def f():
l.append(4)
對(duì)于多層函數(shù)中定義的變量,如果要修改上層變量,可以使用nonlocal的關(guān)鍵字
def f1():
x=1
def f2():
x=2
def f3()
nonlocal x # 此時(shí)修改的是f2中的值
x=3
f3()
f2()
f1()
作用域關(guān)系搬泥,在函數(shù)定義時(shí)就已經(jīng)固定桑寨,與調(diào)用位置無(wú)關(guān)。
x=1
def f1():
def f2():
print(x)
return f2
def foo(func):
x=2
func() # 此處調(diào)用 f1()會(huì)在f1()的作用域中查找x的值忿檩,不會(huì)在foo()作用域中查找尉尾,他們不屬于同一個(gè)name space
foo(f1())
輸出結(jié)果: 1
如果在調(diào)用函數(shù)之前已經(jīng)對(duì)變量重新賦值,則修改生效:
x=1
def f1():
def f2():
print(x)
return f2
def f3(func):
x=2
func()
x=3
f3(f1()) # 在調(diào)用此函數(shù)時(shí)燥透,同一name space中的x已經(jīng)被重新定義
輸出結(jié)果: 3
如果在調(diào)用之后沙咏,再對(duì)同一name space中的變量值進(jìn)行修改,則函數(shù)調(diào)用的值為修改之前的值:
x=1
def f1():
def f2():
print(x)
return f2
def f3(func):
x=2
func()
f3(f1())
x=3
輸出結(jié)果: 1
閉包函數(shù)
由上面作用域的規(guī)律班套,可以總結(jié)出在作用的范圍肢藐,通過(guò)定義返回函數(shù),可以固定參數(shù)的值吱韭,無(wú)論在程序的任何位置調(diào)用吆豹,都可以保證函數(shù)參數(shù)的值不變,這種功能的函數(shù)就叫做閉包函數(shù)理盆,為方便外部的函數(shù)調(diào)用痘煤,使用return的方式返回內(nèi)部的函數(shù)對(duì)象:
def deco():
x=123
def wrapper():
print(x)
return wrapper
func=deco() # func=wrapper
func() #函數(shù)無(wú)論在何時(shí)何處調(diào)用,x的值始終為函數(shù)定義的值。