目錄
繼 'Python 學(xué)習(xí)之路三':
Python 內(nèi)置了很多有用的函數(shù),我們可以直接調(diào)用。
要調(diào)用一個(gè)函數(shù),需要知道函數(shù)的名稱和參數(shù),比如求絕對(duì)值的函數(shù) abs,只有一個(gè)參數(shù)??梢灾苯訌?Python 的官方網(wǎng)站查看文檔:
https://docs.python.org/3/library/functions.html
官網(wǎng) 3.7.2 版本內(nèi)置函數(shù)匯總(截圖):
也可以在交互式命令行通過 help(abs)查看 abs 函數(shù)的幫助信息。調(diào)用 abs 函數(shù):
- >>> abs(100)
- 100
- >>> abs(-100)
- 100
- >>> abs(12.12)
- 12.12
- >>>
調(diào)用函數(shù)的時(shí)候,如果傳入的參數(shù)數(shù)量不對(duì),會(huì)報(bào) TypeError 的錯(cuò)誤,并且 Python 會(huì)明確地告訴你:abs()有且僅有 1 個(gè)參數(shù),但給出了兩個(gè):
- >>> abs(11,22)
- Traceback (most recent call last):
- File '<pyshell#114>', line 1, in <module>
- abs(11,22)
- TypeError: abs() takes exactly one argument (2 given)
- >>>
如果傳入的參數(shù)數(shù)量是對(duì)的,但參數(shù)類型不能被函數(shù)所接受,也會(huì)報(bào) TypeError 的錯(cuò)誤,并且給出錯(cuò)誤信息:str 是錯(cuò)誤的參數(shù)類型:
- >>> abs('a')
- Traceback (most recent call last):
- File '<pyshell#117>', line 1, in <module>
- abs('a')
- TypeError: bad operand type for abs(): 'str'
- >>>
Python 內(nèi)置的常用函數(shù)還包括數(shù)據(jù)類型轉(zhuǎn)換函數(shù),比如 int()函數(shù)可以把其他數(shù)據(jù)類型轉(zhuǎn)換為整數(shù):
- >>> int('321')
- 321
- >>> int(32.1)
- 32
- >>> float('12.12')
- 12.12
- >>> str(12.12)
- '12.12'
- >>> bool(1)
- True
- >>> bool(' ')
- True
- >>> bool(6)
- True
- >>>
函數(shù)名其實(shí)就是指向一個(gè)函數(shù)對(duì)象的引用,完全可以把函數(shù)名賦給一個(gè)變量,相當(dāng)于給這個(gè)函數(shù)起了一個(gè)“別名”:
- >>> a = abs
- >>> a(-1)
- 1
- >>>
在 Python 中,定義一個(gè)函數(shù)要使用 def 語句,依次寫出函數(shù)名、括號(hào)、括號(hào)中的參數(shù)和冒號(hào):,然后,在縮進(jìn)塊中編寫函數(shù)體,函數(shù)的返回值用 return 語句返回。
自定義一個(gè)求絕對(duì)值的 my_abs 函數(shù):
- >>> def my_abs(x) :
- if x >= 0 :
- return x
- else :
- return -x
- >>> print(my_abs(-9))
- 9
- >>>
請(qǐng)注意,函數(shù)體內(nèi)部的語句在執(zhí)行時(shí),一旦執(zhí)行到 return 時(shí),函數(shù)就執(zhí)行完畢,并將結(jié)果返回。因此,函數(shù)內(nèi)部通過條件判斷和循環(huán)可以實(shí)現(xiàn)非常復(fù)雜的邏輯。如果沒有 return 語句,函數(shù)執(zhí)行完畢后也會(huì)返回結(jié)果,只是結(jié)果為 None。return None可以簡寫為 return。
如果你已經(jīng)把 my_abs()的函數(shù)定義保存為 abstest.py 文件了,那么,可以在該文件的當(dāng)前目錄下啟動(dòng) Python 解釋器,用 from abstest import my_abs 來導(dǎo)入 my_abs()函數(shù),注意 abstest 是文件名(不含.py 擴(kuò)展名):
- >>> from abstest import my_abs
- >>> my_aba(-9)
- -9
- >>>
如果想定義一個(gè)什么事也不做的空函數(shù),可以用 pass 語句:
- >>> def nop():
- pass
- >>>
pass 語句什么都不做,那有什么用?實(shí)際上 pass 可以用來作為占位符,比如現(xiàn)在還沒想好怎么寫函數(shù)的代碼,就可以先放一個(gè) pass,讓代碼能運(yùn)行起來。pass 還可以用在其他語句里,比如:
- >>> if age >= 20 :
- pass
- (缺少了 pass,代碼運(yùn)行就會(huì)有語法錯(cuò)誤。)
調(diào)用函數(shù)時(shí),如果參數(shù)個(gè)數(shù)不對(duì),Python 解釋器會(huì)自動(dòng)檢查出來,并拋出TypeError:
- >>> abs('a')
- Traceback (most recent call last):
- File '<pyshell#117>', line 1, in <module>
- abs('a')
- TypeError: bad operand type for abs(): 'str'
- >>>
函數(shù)可以返回多個(gè)值嗎?答案是肯定的。比如在游戲中經(jīng)常需要從一個(gè)點(diǎn)移動(dòng)到另一個(gè)點(diǎn),給出坐標(biāo)、位移和角度,就可以計(jì)算出新的新的坐標(biāo):
- >>> import math
- >>> def move(x,y,step,angle=0):
- nx = x + step * math.cos(angle)
- ny = y - step * math.sin(angle)
- return nx,ny
- >>> x,y = move(100,100,60,math.pi/6)
- >>> print(x,y)
- 151.96152422706632 70.0
- >>>
但其實(shí)這只是一種假象,Python 函數(shù)返回的仍然是單一值:
- >>> m = move(100,100,60,math.pi/6)
- >>> print(m)
- (151.96152422706632, 70.0)
原來返回值是一個(gè) tuple!但是,在語法上,返回一個(gè) tuple 可以省略括號(hào),而多個(gè)變量可以同時(shí)接收一個(gè) tuple,按位置賦給對(duì)應(yīng)的值,所以,Python 的函數(shù)返回多值其實(shí)就是返回一個(gè) tuple,但寫起來更方便。
定義函數(shù)的時(shí)候,把參數(shù)的名字和位置確定下來,函數(shù)的接口定義就完成了。對(duì)于函數(shù)的調(diào)用者來說,只需要知道如何傳遞正確的參數(shù),以及函數(shù)將返回什么樣的值就夠了,函數(shù)內(nèi)部的復(fù)雜邏輯被封裝起來,調(diào)用者無需了解。Python 的函數(shù)定義非常簡單,但靈活度卻非常大。除了正常定義的必選參數(shù)外,還可以使用默認(rèn)參數(shù)、可變參數(shù)和關(guān)鍵字參數(shù),使得函數(shù)定義出來的接口,不但能處理復(fù)雜的參數(shù),還可以簡化調(diào)用者的代碼。
- >>> def power(x) :
- return x * x
- >>> power(3)
- 9
- >>>
對(duì)于 power(x)函數(shù),參數(shù) x 就是一個(gè)位置參數(shù)。當(dāng)我們調(diào)用 power 函數(shù)時(shí),必須傳入有且僅有的一個(gè)參數(shù) x:
那么,可以把 power(x)修改為 power(x, n),用來計(jì)算 x的n次方:
- >>> power(5,2)
- 5
- >>> def power(x,n):
- s = 1
- while n > 0 :
- n = n -1
- s = s*x
- return s
- >>> power(5,2)
- 25
- >>> power(3,5)
- 243
- >>>
修改后的 power(x, n)函數(shù)有兩個(gè)參數(shù):x 和 n,這兩個(gè)參數(shù)都是位置參數(shù),調(diào)用函數(shù)時(shí),傳入的兩個(gè)值按照位置順序依次賦給參數(shù) x 和 n。
新的 power(x, n)函數(shù)定義沒有問題,但是,舊的調(diào)用代碼失敗了,原因是我們?cè)黾恿艘粋€(gè)參數(shù),導(dǎo)致舊的代碼因?yàn)槿鄙僖粋€(gè)參數(shù)而無法正常調(diào)用:
- >>> power(2)
- Traceback (most recent call last):
- File '<pyshell#189>', line 1, in <module>
- power(2)
- TypeError: power() missing 1 required positional argument: 'n'
- >>>
Python 的錯(cuò)誤信息很明確:調(diào)用函數(shù) power()缺少了一個(gè)位置參數(shù) n。這個(gè)時(shí)候,默認(rèn)參數(shù)就排上用場了。由于我們經(jīng)常計(jì)算 x2,所以,完全可以把第二個(gè)參數(shù) n 的默認(rèn)值設(shè)定為 2:
- >>> def power(x,n = 2):
- s = 1
- while n > 0:
- n = n - 1
- s = s * x
- return s
- >>> power(2)
- 4
- >>> power(2,5)
- 32
- >>>
從上面的例子可以看出,默認(rèn)參數(shù)可以簡化函數(shù)的調(diào)用。設(shè)置默認(rèn)參數(shù)時(shí),有幾點(diǎn)要注意:
當(dāng)函數(shù)有多個(gè)參數(shù)時(shí),把變化大的參數(shù)放前面,變化小的參數(shù)放后面。變化小的參數(shù)就可以作為默認(rèn)參數(shù)。使用默認(rèn)參數(shù)有什么好處?最大的好處是能降低調(diào)用函數(shù)的難度。
在 Python 函數(shù)中,還可以定義可變參數(shù)。顧名思義,可變參數(shù)就是傳入的參數(shù)個(gè)數(shù)是可變的,可以是 1 個(gè)、2 個(gè)到任意個(gè),還可以是 0 個(gè)。
以數(shù)學(xué)題為例子,給定一組數(shù)字 a,b,c……,請(qǐng)計(jì)算 a2 + b2 + c2 + ……。要定義出這個(gè)函數(shù),我們必須確定輸入的參數(shù)。由于參數(shù)個(gè)數(shù)不確定,首先想到可以把a(bǔ),b,c……作為一個(gè) list 或 tuple 傳進(jìn)來,這樣,函數(shù)可以定義如下:
- >>> def calc(nums):
- sum = 0
- for n in nums:
- sum = sum + n * n
- return sum
- >>> calc([1,2,3,4])
- 30
- >>> def calc(*num):
- sum = 0
- for n in num:
- sum += n * n
- return sum
- >>> calc (1,2)
- 5
- >>> calc(3)
- 9
- >>>
定義可變參數(shù)和定義一個(gè) list 或 tuple 參數(shù)相比,僅僅在參數(shù)前面加了一個(gè)*號(hào)。在函數(shù)內(nèi)部,參數(shù) numbers 接收到的是一個(gè) tuple,因此,函數(shù)代碼完全不變。但是,調(diào)用該函數(shù)時(shí),可以傳入任意個(gè)參數(shù),包括 0 個(gè)參數(shù):
- >>> calc (1,2)
- 5
- >>> calc(3)
- 9
- >>> calc()
- 0
- >>>
*nums 表示把 nums 這個(gè) list 的所有元素作為可變參數(shù)傳進(jìn)去。這種寫法相當(dāng)有用,而且很常見。
可變參數(shù)允許你傳入 0 個(gè)或任意個(gè)參數(shù),這些可變參數(shù)在函數(shù)調(diào)用時(shí)自動(dòng)組裝為一個(gè)tuple。而關(guān)鍵字參數(shù)允許你傳入 0 個(gè)或任意個(gè)含參數(shù)名的參數(shù),這些關(guān)鍵字參數(shù)在函數(shù)內(nèi)部自動(dòng)組裝為一個(gè) dict。
- >>> def person(name,age,**kg):
- print('name:',name,'age:',age,'other',kg)
- >>> person('Jerry',20)
- name: Jerry age: 20 other {}
- >>> person('Jerry',20,city='shanghai')
- name: Jerry age: 20 other {'city': 'shanghai'}
- >>>
函數(shù) person 除了必選參數(shù) name 和 age 外,還接受關(guān)鍵字參數(shù) kg。在調(diào)用該函數(shù)時(shí),可以只傳入必選參數(shù):
- >>> person('Jerry',20,city='shanghai',job='Enginner')
- name: Jerry age: 20 other {'city': 'shanghai', 'job': 'Enginner'}
- >>>
關(guān)鍵字參數(shù)有什么用?它可以擴(kuò)展函數(shù)的功能。比如,在 person 函數(shù)里,保證能接收到 name 和 age 這兩個(gè)參數(shù),但是,如果調(diào)用者愿意提供更多的參數(shù),也能收到。試想正在做一個(gè)用戶注冊(cè)的功能,除了用戶名和年齡是必填項(xiàng)外,其他都是可選項(xiàng),利用關(guān)鍵字參數(shù)來定義這個(gè)函數(shù)就能滿足注冊(cè)的需求。
**extra 表示把 extra 這個(gè) dict 的所有 key-value 用關(guān)鍵字參數(shù)傳入到函數(shù)的**kw 參數(shù),kw 將獲得一個(gè) dict,注意 kw 獲得的 dict 是 extra 的一份拷貝,對(duì) kw 的改動(dòng)不會(huì)影響到函數(shù)外的 extra。
(待整理)
聯(lián)系客服