1. 函數(shù)介紹
??函數(shù) 在編程語言中就是完成特定功能的一個(gè)詞句組 (代碼塊)作谭,這組語句可以作為一個(gè)單位使用萍桌,并且給它取一個(gè)名字匕积∪楣妫可以通過函數(shù)名在程序的不同地方多次執(zhí)行(這叫 函數(shù)的調(diào)用)。函數(shù)在編程語言中有基本分為:預(yù)定義函數(shù)
,自定義函數(shù)
。預(yù)定義函數(shù)可以直接使用沃暗,而自定義函數(shù)顧名思義需要我們自己定義函數(shù)。
在數(shù)學(xué)中的定義何恶,這里就不介紹了孽锥。請參考 函數(shù)(數(shù)學(xué)函數(shù))_百度百科
1.1. 為什么要使用函數(shù)
在編程中使用函數(shù)主要有兩個(gè)優(yōu)點(diǎn):
- 降低編程難度:通常將一個(gè)復(fù)雜的大問題分解成一系列的小問題,然后將小問題劃分成更小的問題细层,當(dāng)問題細(xì)化為足夠簡單時(shí)惜辑,我們就可以分而治之,各個(gè)小問題解決了疫赎,大問題就迎刃而解了盛撑。
- 代碼重用:避免重復(fù)勞作,提供效率
- 代碼更加簡潔美觀捧搞,可讀性增加
1.2. Python 中的函數(shù)
??在 Python 中抵卫,函數(shù)由 若干語句組成的代碼塊
、函數(shù)名稱
胎撇、參數(shù)列表
構(gòu)成介粘,它是組織代碼的最小單元,使用函數(shù)可以完成一定的功能晚树,在 Python 中函數(shù)主要分為三類:內(nèi)置函數(shù)
姻采、第三方函數(shù)庫
、自定義函數(shù)
爵憎。常用的內(nèi)置函數(shù)在前面已經(jīng)介紹慨亲,第三方函數(shù)庫需要先引入模塊婚瓜,通過模塊調(diào)用,在模塊學(xué)習(xí)中進(jìn)行介紹巡雨,這里主要說的是如何自定義一個(gè)函數(shù)闰渔。
2. 函數(shù)的基本使用
??在 Python 中席函,定義一個(gè)函數(shù)要使用 def 語句铐望,依次寫出 函數(shù)名
、括號
茂附、括號中的參數(shù)
和冒號:
正蛙,然后,在縮進(jìn)塊中編寫函數(shù)體营曼,函數(shù)的返回值用 return 語句
返回乒验。下面是一個(gè)函數(shù)的基本結(jié)構(gòu):
def 函數(shù)名(參數(shù)列表):
函數(shù)體(代碼塊)
[return 返回值] # 函數(shù)可以無返回值
注意:
-
函數(shù)名
就是標(biāo)識符
,命名要求一樣 -
語句塊
必須縮進(jìn)蒂阱,約定4 個(gè)空格
- Python 的函數(shù)可以沒有 return 語句锻全,會隱式地返回一個(gè) None
- 定義中的參數(shù)列表稱為
形式參數(shù)
,只是一種符號表達(dá)式(標(biāo)識符)录煤,簡稱形參
??我們以自定義一個(gè)求絕對值的函數(shù)為例:
In : def abs(x):
...: if x >= 0:
...: return x
...: else:
...: return -x
...:
In : abs(-10)
Out: 10
In : abs
Out: <function __main__.abs(x)>
In : print(abs)
<function abs at 0x0000027021055E18>
??上面只是一個(gè)函數(shù)的定義鳄厌,具體來看一下各個(gè)部分的解釋:
- 函數(shù)名字叫做 abs,接受 1 個(gè)形式參數(shù) x妈踊。
- return x: 表示要返回的值是 x了嚎,函數(shù)可以無返回值。
- 函數(shù)是一個(gè)
可調(diào)用對象
廊营,函數(shù)名加括號
就表示調(diào)用歪泳。 - 和變量的使用方式相同,在使用函數(shù)時(shí)露筒,需要預(yù)先進(jìn)行定義呐伞。
- 直接打印函數(shù)名,不會觸發(fā)函數(shù)的執(zhí)行慎式,反而會打印函數(shù)的內(nèi)存地址伶氢。
??我們自定義的函數(shù) abs, 由于與內(nèi)置函數(shù)重名,那么將會覆蓋掉內(nèi)置函數(shù)瞬捕,所以請謹(jǐn)慎命名鞍历。
??函數(shù)體內(nèi)部的語句在執(zhí)行時(shí),一旦執(zhí)行到 return 時(shí)肪虎,函數(shù)就執(zhí)行完畢劣砍,并將結(jié)果返回。因此扇救,函數(shù)內(nèi)部通過條件判斷和循環(huán)可以實(shí)現(xiàn)非常復(fù)雜的邏輯刑枝。如果沒有 return 語句香嗓,函數(shù)執(zhí)行完畢后會隱式地返回 None
。如果我們確實(shí)要 return None
可以簡寫為 return
装畅,或者不寫 return 語句
(會讓人看不懂靠娱,建議只寫 return
)。
??調(diào)用函數(shù)掠兄,那么只需要使用函數(shù)名加括號像云,就能執(zhí)行,但如果函數(shù)定義了參數(shù)蚂夕,那么必須在執(zhí)行的時(shí)候傳遞參數(shù)給函數(shù)迅诬,否則會報(bào)異常!關(guān)于調(diào)用我們還需要了解:
- 函數(shù)定義婿牍,只是聲明了一個(gè)函數(shù)侈贷,它不會被執(zhí)行,調(diào)用時(shí)才會執(zhí)行
- 調(diào)用方式就是函數(shù)名后加上小括號等脂,如果有必要需要在括號內(nèi)寫上參數(shù)
- 調(diào)用時(shí)寫的參數(shù)是實(shí)際參數(shù)俏蛮,是實(shí)實(shí)在在傳入的值,簡稱實(shí)參
函數(shù)是可調(diào)用對象上遥,可以使用 callable() 進(jìn)行判斷
In : def abs(x):
...: if x >= 0:
...: return x
...: else:
...: return -x
# 函數(shù)是可調(diào)用的搏屑,注意這里不能對函數(shù)加括號,那么 callable 判斷的就是函數(shù)的返回值是否可以執(zhí)行了
In : callable(abs)
Out: True
# 字符串是不可調(diào)用的
In : a = '123'
In : callable(a)
Out: False
3. 函數(shù)的參數(shù)
??定義函數(shù)的時(shí)候露该,括號中指定的就是函數(shù)的參數(shù) (形式參數(shù))睬棚,當(dāng)我們調(diào)用函數(shù)時(shí),需要將數(shù)據(jù)進(jìn)行傳遞解幼,這種傳遞參數(shù)的方式就叫做傳參抑党,嚴(yán)格來說函數(shù)只可以使用兩種方式:位置傳參
和 關(guān)鍵字傳參
。
-
位置傳參
:按照參數(shù)定義順序傳入實(shí)參撵摆,位置參數(shù)是按位置對應(yīng)的 -
關(guān)鍵字傳參
:使用形參的名字來傳入實(shí)參的方式底靠,如果使用了形參的名字
,那么傳入?yún)?shù)的順序就可以和定義的順序
不同 - 當(dāng)
位置傳參
和關(guān)鍵字傳參
混用時(shí)特铝,位置參數(shù)必須在關(guān)鍵字參數(shù)之前傳入暑中。
# 定義函數(shù) function:
In : def function(x, y):
...: result = x + y
...: return result
...:
# 位置傳參: # 1 對應(yīng) x,2 對應(yīng) y鲫剿。
In : function(1, 2)
Out: 3
# 關(guān)鍵字傳參: 使用關(guān)鍵字時(shí)鳄逾,參數(shù)可以不用按照位置順序。
In : function(y=1, x=2)
Out: 3
# 混合傳參: 混用時(shí)灵莲,關(guān)鍵字參數(shù)必須要再位置參數(shù)右邊
In : function(1, y = 3)
Out: 4
3.1. 參數(shù)的缺省值
??在定義形式參數(shù)時(shí)雕凹,為參數(shù)指定對應(yīng)的值,就叫做參數(shù)的缺省值,當(dāng)定義了參數(shù)的缺省值以后枚抵,我們傳參時(shí)可以選擇傳遞該參數(shù)的值线欲,也可以選擇不傳遞,當(dāng) 不傳遞
此參數(shù)的值時(shí)汽摹,該參數(shù)就使用指定的 缺省值
李丰,否則
將會使用 傳遞的值
。
參數(shù)缺省值也屬于位置參數(shù)逼泣,只不過是給位置參數(shù)定義了默認(rèn)值趴泌。
In : def function(x = 10, y = 20):
...: return x + y
...:
# 2 會以位置參數(shù)的形式傳遞給 x,y 沒有傳遞圾旨,會使用缺省值
In : function(2)
Out: 22
# x 沒有傳遞踱讨,會使用缺省值
In : function(y=100)
Out: 110
# y 沒有傳遞魏蔗,會使用缺省值
In : function(x=100)
Out: 120
# 20 以位置參數(shù)的形式傳遞給 x砍的,500 以關(guān)鍵字參數(shù)的形式傳遞給了 y
In : function(20, y=500)
Out: 520
當(dāng)定義參數(shù)的缺省值時(shí),注意
缺省值參數(shù)
必須要放在位置參數(shù)的右邊
# 必須把 x=1莺治,放在 y 的右邊廓鞠,否則無法完成函數(shù)定義
In : def functions(x=1, y):
...: print(x+y)
File "<ipython-input-1-ea496fa7fc81>", line 1
def functions(x=1, y):
^
SyntaxError: non-default argument follows default argument
使用缺省值參數(shù)的好處是:
- 參數(shù)的缺省值可以在未傳入足夠的實(shí)參的時(shí)候,對沒有給定的參數(shù)賦值為缺省值谣旁。
- 參數(shù)非常多的時(shí)候床佳,并不需要用戶每次都輸入所有的參數(shù),簡化函數(shù)調(diào)用榄审。
3.2. 可變參數(shù)
??可變參數(shù)顧名思義表示參數(shù)的數(shù)量是可變的砌们,并且可以使用一個(gè)形參匹配任意個(gè)實(shí)參。針對傳遞參數(shù)方式的不同又分為 可變位置傳參
和 可變關(guān)鍵字傳參
搁进。
3.2.1. 可變位置傳參
??在形參前使用 *
號浪感,表示該形參是可變參數(shù),可以接受多個(gè)實(shí)參饼问,在函數(shù)內(nèi)部影兽,可變參數(shù)會封裝成元組 (即便是沒有傳遞)
In : def function(*nums):
...: print(nums)
...:
In : function(1,2,3,4) # 多個(gè)參數(shù)會被 nums 收集
(1, 2, 3, 4)
In : function([1,2,3,4]) # 會把 list 收集成元組內(nèi)的一個(gè)元素
([1, 2, 3, 4],)
在函數(shù)定義時(shí),一般的規(guī)范是使用
*args
, 表示收集多個(gè)位置傳參莱革。
3.2.2. 可變關(guān)鍵字傳參
??在形參前使用 **
號峻堰,表示該形參是可變關(guān)鍵字參數(shù),可以接受多個(gè)關(guān)鍵字參數(shù)盅视,在函數(shù)內(nèi)部捐名,可變關(guān)鍵字參數(shù)會封裝成字典 (即便是沒有傳遞)
In : def function(**kwargs):
...: print(kwargs)
...:
In : function(a=1,b=2)
{'a': 1, 'b': 2}
# 參數(shù)的缺省值和位置參數(shù)同時(shí)使用
In : def function(x=1, y=2, **kwargs):
...: print('x = {}'.format(x))
...: print('y = {}'.format(y))
...: print(kwargs)
...:
# 參數(shù)沒有 a,b 形參闹击,則被 kwargs 接收
In : function(a=10, b=20)
x = 1
y = 2
{'a': 10, 'b': 20}
# z 沒有被匹配镶蹋,被 kwargs 接收
In : function(x=100,y=200,z=300)
x = 100
y = 200
{'z': 300}
# 前面的按照位置參數(shù)賦值,z 同樣被字典 kwargs 收集
In : function(1000,2000,z=300)
x = 1000
y = 2000
{'z': 300}
3.2.3. 可變參數(shù)混合使用
??前面說的各種參數(shù)是可以混合使用的,當(dāng)混合使用時(shí)遵循一定的順序梅忌,簡單總結(jié)一下狰腌,按照從左至右的順序來說:位置參數(shù),缺省值參數(shù)牧氮,可變位置參數(shù)琼腔,可變關(guān)鍵字參數(shù):
def function(位置參數(shù),缺省值參數(shù)踱葛,可變位置參數(shù)丹莲,可變關(guān)鍵字參數(shù)):
??無論如何,順序不能顛倒尸诽。
# x,y,z 都為位置參數(shù)甥材,z 的缺省值為 1,*args 收集額外的位置傳參性含,**kwargs 收集額外的關(guān)鍵字傳參
In : def function(x,y,z=1,*args,**kwargs):
...: print(x,y,z)
...: print(args)
...: print(kwargs)
...:
In : function(1,2,3,4,5,a=1,b=2)
1 2 3
(4, 5)
{'a': 1, 'b': 2}
3.2.4. 可變參數(shù)小結(jié)
??針對可變參數(shù)以及不同的混用方式可以有如下結(jié)論:
- 分為
可變位置參數(shù)
和可變關(guān)鍵字參數(shù)
-
可變位置參數(shù)
在形參前使用一個(gè)星號 *
-
可變關(guān)鍵字參數(shù)
在形參前使用兩個(gè)星號 **
-
可變位置參數(shù)
和可變關(guān)鍵字參數(shù)
都可以收集若干個(gè)實(shí)參洲赵,可變位置參數(shù)
收集形成一個(gè)tuple
,可變關(guān)鍵字參數(shù)
收集形成一個(gè)dict
- 混合使用參數(shù)的時(shí)候商蕴,在定義階段要遵循如下順序:
位置參數(shù)
叠萍,缺省值參數(shù)
,可變位置參數(shù)
绪商,可變關(guān)鍵字參數(shù)
??當(dāng)位置傳參和關(guān)鍵字傳參同時(shí)使用時(shí)苛谷,針對同一個(gè)形參不可以重復(fù)賦值!格郁,這一點(diǎn)使用的時(shí)候很重要腹殿。
3.3. keyword-only 參數(shù) *
??Python3 的函數(shù)參數(shù)中,新增了 keyword-only 參數(shù)
例书,什么叫 keyword-only 參數(shù)
锣尉? 當(dāng)在一個(gè)星號參數(shù) (可變位置參數(shù)) 后,出現(xiàn)的普通參數(shù)雾叭,我們稱它為 keyword-only 參數(shù)悟耘,因?yàn)槎嘤嗟奈恢脜?shù)都會被 *args
收集,只能通過 keyword 的方式對這些形參進(jìn)行賦值织狐,所以它們只能使用 關(guān)鍵字傳參
暂幼。
# x,y 是 keyword-only 參數(shù),其中 y 存在缺省值移迫,可以不用傳遞旺嬉,x 必須使用關(guān)鍵字的方式進(jìn)行傳遞
In : def function(a, b, c=1, *args, x, y=2, **kwargs):
...: print(a,b,c)
...: print(args)
...: print(x,y)
...: print(kwargs)
...:
In : function(100,200,300,400,d=100,e=200)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-cf60009e3d1f> in <module>
----> 1 function(100,200,300,400,d=100,e=200)
TypeError: function() missing 1 required keyword-only argument: 'x'
In : function(100,200,300,400,d=100,e=200,x=500)
100 200 300
(400,)
500 2
{'d': 100, 'e': 200}
特殊形式:
In : def function(*, x, y):
...: print(x,y)
...:
In : function(1, 2, 3, x=100, y=200)
---------------------------------------------------------------------------
TypeError Traceback(most recent call last)
<ipython-input-18-7d07ae79c088> in <module>
----> 1 function(1,2,3,x=100,y=200)
TypeError: function() takes 0 positional arguments but 3 positional arguments(and 2 keyword-only arguments) were given
In : function(x=100, y=200)
100 200
這里 * 表示不接受位置傳參,只能使用關(guān)鍵字對參數(shù)進(jìn)行賦值
??注意: 使用了 keyword-only 參數(shù)
厨埋,那么在定義形參時(shí)的順序就有所改變了邪媳,它們是:位置參數(shù),缺省值參數(shù),可變位置參數(shù)雨效,keyword-only 參數(shù)迅涮,可變關(guān)鍵字參數(shù)
4.1. 參數(shù)解構(gòu)
前面我們說過 Python 的封裝與結(jié)構(gòu),這里的參數(shù)也可以利用這種思想進(jìn)行解構(gòu)徽龟,現(xiàn)有如下函數(shù):
In : def add(x=1, y=2):
...: print(x+y)
...:
# 將元組的元素 1 和元素 2 分別傳給 x叮姑,y
In : t = (10,20)
In : add(t[0], t[1])
30
# 非字典類型使用 * 解構(gòu)成位置參數(shù)
In : add(*t)
30
# 字典型使用 ** 解構(gòu)成關(guān)鍵字參數(shù)
In : d = {'x':100, 'y':200}
In : add(**d)
300
- 將 t 在傳遞參數(shù)時(shí)解構(gòu)為
10,20
据悔,作為位置傳參
傳遞給 add 函數(shù) - 將 d 在傳遞參數(shù)時(shí)解構(gòu)為
x=100,y=200
传透,作為關(guān)鍵字傳參
傳遞給函數(shù) - 這種方法在后面函數(shù)的調(diào)用過程中非常常用
??現(xiàn)在再來回頭看一下,什么時(shí)參數(shù)解構(gòu)极颓?
- 給函數(shù)提供實(shí)參的時(shí)候朱盐,可以在集合類型前使用
*
或者**
,把集合類型的結(jié)構(gòu)解開菠隆,提取出其中所有元素作為函數(shù)的實(shí)參 - 非字典類型使用
* 解構(gòu)成位置參數(shù)
- 字典型使用
** 解構(gòu)成關(guān)鍵字參數(shù)
- 提取出來的元素?cái)?shù)目要和參數(shù)的要求匹配兵琳,也要和參數(shù)的類型匹配,否則請使用
*args
,**kwargs
In : def add(a,b,*args,m,n,**kwargs):
...: print(a + b + m + n)
...:
In : dic = {'a':100,'b':200}
In : add(**dic,m=300,n=400,x=1000)
1000
5. 函數(shù)的返回值
??我們通常編寫函數(shù)除了代碼可以復(fù)用浸赫,更多的時(shí)候需要的是知道函數(shù)的運(yùn)算結(jié)果闰围,函數(shù)把運(yùn)算的結(jié)果返回給我們,這個(gè)結(jié)果就叫作做函數(shù)的返回值
既峡。使用 return
關(guān)鍵字進(jìn)行返回。
# 返回 1 個(gè)數(shù)據(jù)
In : def add(x,y):
...: result = x + y
...: return result
...:
In : a = add(10,20)
In : print(a)
30
# 返回多個(gè)數(shù)據(jù)
In : def add(x,y):
...: result = x + y
...: test = x * y
...: return result,test
...:
In : a = add(10,20)
In : print(a)
(30, 200)
# 多個(gè) return 語句
In : def bigger(x,y):
...: if y > x:
...: return y
...: else:
...: return x
...:
In : a = bigger(10,20)
In : print(a)
20
總結(jié):
- Python 函數(shù)使用
return
語句返回 "返回值" - 所有函數(shù)都有返回值碧查,如果沒有
return
語句运敢,隱式調(diào)用return None
-
return
語句并不一定是函數(shù)的語句塊的最后一條語句 - 一個(gè)函數(shù)可以存在多個(gè)
return
語句,但是只有一條可以被執(zhí)行忠售,如果沒有一條return
語句被執(zhí)行传惠,隱式調(diào)用return None
5.return None
可以簡寫為 return - 函數(shù)執(zhí)行到
return
就會返回,所以return
后面的語句永遠(yuǎn)不會被執(zhí)行 -
return
可以理解為稻扬,結(jié)束當(dāng)前函數(shù)計(jì)算卦方,返回值!
函數(shù)永遠(yuǎn)只能返回一個(gè)數(shù)據(jù)泰佳。
- 返回值數(shù)量 = 0盼砍,即
return
(或者不寫return
語句),返回的數(shù)據(jù)為None
逝她。 - 返回值數(shù)量 = 1浇坐,返回 object(一個(gè)對象)。
- 返回值數(shù)量 > 1黔宛,返回 tuple(一個(gè)元組)近刘。