當編寫的代碼出現有規律的重複時,這個時候就要考慮定義函數,將這些代碼提取定義成一個函數,方便調用。html
Python 提供許多內置函數,能夠根據須要調用相應的函數實現想要的功能。一樣 Python 也可以靈活地自定義函數。python
介紹如何定義函數前,先講下如何調用函數。微信
Python 提供許多內置函數,這些函數都是能夠直接調用的。包括前面的篇幅,其實也有調用函數實現一些功能。這裏大體講下函數的調用。app
舉個例子,求絕對值的函數 abs()
,這個函數只接受一個參數。函數的使用能夠查看官方文檔:ide
http://docs.python.org/3/library/functions.html#abs函數
也能夠在交互式命令行下經過 help(abs)
來查看 abs
函數的幫助信息。測試
如今嘗試調用 abs()
函數:ui
>>> abs(-1) 1 >>> abs(1) 1
由於 abs
只接受一個參數,如果傳入的參數個數不爲 1,會報 TypeError
的錯誤,信息中也會給出錯誤的提示:idea
>>> abs(-1, 1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: abs() takes exactly one argument (2 given)
這裏表示,abs()
函數只接受一個參數,可是卻提供了兩個參數。命令行
abs()
的參數接收的是數值,如果傳入的類型錯誤,一樣也會報錯:
>>> abs('1') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: bad operand type for abs(): 'str'
這裏給出的錯誤提示表示 str
不是可接受的類型。
這就是函數調用,同時也須要注意的一些地方。要了解函數調用須要的幾個參數,以及參數的類型。
如今講一下函數的定義,函數定義要使用 def
語句,後面緊跟的是函數名,括號,包含在括號內的參數以及冒號,而後在縮進塊編寫函數體,若是有返回值的話,則使用 return
語句返回。
仍是以求絕對值爲例,這裏自定義函數實現:
def my_abs(num): if num >= 0: return num else: return -num
當執行 return
時,函數即爲執行完畢,直接返回結果。例子中,簡單使用了條件判斷,函數內部能夠經過使用條件判斷以及循環,實現很是複雜的邏輯。
有些函數並無 return
語句。可是函數執行完畢後一樣會返回結果,只是結果爲 None。因此 return None
,也能夠寫爲 return
。
如今咱們嘗試調用本身編寫的函數 my_abs
:
>>> my_abs(1) 1 >>> my_abs(-1) 1 >>> my_abs('a') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in my_abs TypeError: '>=' not supported between instances of 'str' and 'int'
這裏會看到當參數接受字符串的時候,出現的錯誤與 Python 提供的 abs
出錯信息不同。
這裏咱們添加對參數的檢查,只容許整數和浮點數類型的參數。能夠用 isinstance()
函數實現數據類型檢查。
>>> def my_abs(num): ... if not isinstance(num, (int, float)): ... raise TypeError("bad operand type") ... if num >= 0: ... return num ... else: ... return -num ...
再次嘗試調用該函數:
>>> my_abs('1') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in my_abs TypeError: bad operand type
這樣,看起來就更像 abs()
函數。
有時候,可能並無想好要編寫怎樣的函數,可是想先定義,在後續補充代碼。這個時候,pass 語句就派上用場。
pass 語句可以作佔位符使用,能夠在函數體中先將這個語句放進來,讓編寫的其餘代碼運行起來。等到後續要補充的時候再去掉 pass 語句進行修改。例如:
def no_idea(): pass
這裏若是函數體內沒有這個 pass 語句,運行就會提示有語法錯誤。
上面說起的自定義函數,包括帶 pass 語句的空函數(返回的是 None),返回的是一個值。
爲了能夠返回多個值,能夠直接返回一個元組,例如:
>>> def my_func(): ... return 1, 2, 3 ... >>> a, b, c = my_func() >>> a 1 >>> b 2 >>> c 3
雖然上面的函數看上去是返回了多個值,但其實是先建立一個元組而後返回的。
其實咱們使用的是逗號來生成一個元組,而不是用括號。例如:
>>> a = (1,2) # 帶括號 >>> a (1, 2) >>> b = 1,2 # 不帶括號 >>> b (1, 2)
因此,這前面定義返回多值的函數,其實返回的是元組。如果賦值給單個變量,那麼這個變量其實就是返回的那個元組自己:
>>> d = my_func() >>> d (1, 2, 3)
先定義一個函數:
>>> def func(a, b): ... print('a = {},b = {}'.format(a, b)) ... >>> func(1,2) a = 1,b = 2
在這裏,就是 a
和 b
,兩個參數都是位置參數,調用的時候,依次將兩個值按照順序依次賦值給參數 a
和 b
。
延用上面的例子,在這裏,咱們調用的時候只賦值給 a:
>>> func(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: func() missing 1 required positional argument: 'b'
這裏錯誤提示:調用參數缺乏一個位置參數 b
。
這個時候,就能夠考慮使用默認參數:
>>> def func(a, b=2): ... print('a = {}, b = {}'.format(a, b)) ... >>> func(1) a = 1, b = 2
能夠看到當調用 func(1)
時,就至關於調用了 func(1, 2)
。
這裏有些地方須要注意:
第一點比較好理解,若是默認參數在必選參數前面,因爲傳入的值會按照位置給參數賦值。例以下面的錯誤示例(下面這種寫法僅作錯誤示範,不建議如此編寫。固然這樣編寫也會報錯):
def func(a=1, b): return a, b
假設咱們調用的時候,以這樣的邏輯想,如今 a
有默認值,只給 b
賦值就能夠了。可是賦值會按照位置賦值。好比調用 func(2)
,其實這裏是將 2
賦值給了 a
,替代了原來的 1
,最終 b
仍是缺乏賦值。
第二點,必須指向不變對象,千萬不能像下面這樣編寫代碼:
def func(a, b=[]): ....
這樣寫的話,後面會遇到不少的麻煩。b
做爲可修改的對象,這些修改會影響到下次調用這個函數的默認值。好比:
>>> def func(a, b=[]): ... print(b) ... return b ... >>> x = func(1) [] >>> x.append(2) >>> x.append('wow!') >>> x [2, 'wow!'] >>> func(1) [2, 'wow!']
能夠看到當再次調用 func(1)
的時候,結果已經變了,這個並非原來的初衷。
若是真的須要使用列表,最好先使用 None
,而後在函數裏面用相應的邏輯檢查。
固然測試 None 的時候要須要注意,使用 is
操做符是很是重要的。
def func(a, b=None): if not b: # 不建議這樣寫,建議用 b is None:代替 b = []
上面不建議使用 if not b:
,若是這樣的話,None 會被當成是 False,而長度爲 0 的字符串,列表,元組,字典等均可能被當成 False。這一點也要注意。
上面說起的函數都是固定數量的位置參數,爲了實現一個能接受任意數量的位置參數的函數,可使用一個 *
參數。例如:
>>> def func(*nums): ... sum = 0 ... for num in nums: ... sum += num ... return sum ... >>> func(1,2) 3 >>> func(1,2,3) 6
這樣就實現了能夠傳入任意數量的參數的位置參數。
如果要實現接受任意數量的關鍵字參數,可使用 **
開頭的參數。好比:
>>> def info(name, age, **kw): ... print('name:', name, 'age:', age, 'other:', kw) ... >>> info('大夢三千秋', 0) name: 大夢三千秋 age: 0 other: {} >>> info('大夢三千秋', 0, city='Guangzhou') name: 大夢三千秋 age: 0 other: {'city': 'Guangzhou'} >>> info('大夢三千秋', 0, city='Guangzhou', gender='male') name: 大夢三千秋 age: 0 other: {'city': 'Guangzhou', 'gender': 'male'}
這樣就實現了傳入任意個數的關鍵字參數。這裏,關鍵字參數容許傳入 0 個或任意個參數名的參數,函數內部會自動組成一個 dict,如上示例。
命名關鍵字參數,實際上是將關鍵字參數放到某個 *
參數後面或者單個 *
後面,例如:
>>> def info(name, age, *, city): ... print(name, age, city) ... >>> info('大夢三千秋', 0, city='Guangzhou') 大夢三千秋 0 Guangzhou
這裏注意調用方式,必定要傳入參數名,如果沒有傳入參數名,則會報錯:
>>> info('大夢三千秋', 0, 'Guangzhou') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: info() takes 2 positional arguments but 3 were given
上面的提示中說只須要 2 個位置參數,可是傳入的參數有 3 個。這時由於缺乏參數名 city
,解釋器將 3 個參數都視爲位置參數,但 info
函數只接受 2 個位置參數。
這裏說起到的參數有位置(必選)參數、默認參數、可變參數、關鍵字參數和命名關鍵字參數。可是須要注意參數的定義順序:
必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。
雖然上面的參數均可以組合在一塊兒,可是不建議這樣作,這樣會致使可理解性變差。
以上就是關於函數的定義,調用以及函數參數的一些內容。
歡迎關注微信公衆號《書所集錄》