Python_9_函數(shù)定義-位置參數(shù)-返回值

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):

  1. 降低編程難度:通常將一個(gè)復(fù)雜的大問題分解成一系列的小問題,然后將小問題劃分成更小的問題,當(dāng)問題細(xì)化為足夠簡單時(shí),我們就可以分而治之,各個(gè)小問題解決了,大問題就迎刃而解了。
  2. 代碼重用:避免重復(fù)勞作,提供效率
  3. 代碼更加簡潔美觀,可讀性增加

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ù)名、括號(hào)、括號(hào)中的參數(shù)冒號(hào):,然后,在縮進(jìn)塊中編寫函數(shù)體,函數(shù)的返回值用 return 語句 返回。下面是一個(gè)函數(shù)的基本結(jié)構(gòu):

def 函數(shù)名(參數(shù)列表):
    函數(shù)體(代碼塊)
    [return 返回值]   # 函數(shù)可以無返回值

注意:

  • 函數(shù)名 就是 標(biāo)識(shí)符,命名要求一樣
  • 語句塊 必須縮進(jìn),約定 4 個(gè)空格
  • Python 的函數(shù)可以沒有 return 語句,會(huì)隱式地返回一個(gè) None
  • 定義中的參數(shù)列表稱為形式參數(shù),只是一種符號(hào)表達(dá)式(標(biāo)識(shí)符),簡稱 形參

??我們以自定義一個(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ù)名 加括號(hào) 就表示調(diào)用。
  • 和變量的使用方式相同,在使用函數(shù)時(shí),需要預(yù)先進(jìn)行定義。
  • 直接打印函數(shù)名,不會(huì)觸發(fā)函數(shù)的執(zhí)行,反而會(huì)打印函數(shù)的內(nèi)存地址。

??我們自定義的函數(shù) abs, 由于與內(nèi)置函數(shù)重名,那么將會(huì)覆蓋掉內(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í)行完畢后會(huì)隱式地返回 None。如果我們確實(shí)要 return None 可以簡寫為 return,或者不寫 return 語句 (會(huì)讓人看不懂,建議只寫 return)。
??調(diào)用函數(shù),那么只需要使用函數(shù)名加括號(hào),就能執(zhí)行,但如果函數(shù)定義了參數(shù),那么必須在執(zhí)行的時(shí)候傳遞參數(shù)給函數(shù),否則會(huì)報(bào)異常!關(guān)于調(diào)用我們還需要了解:

  1. 函數(shù)定義,只是聲明了一個(gè)函數(shù),它不會(huì)被執(zhí)行,調(diào)用時(shí)才會(huì)執(zhí)行
  2. 調(diào)用方式就是函數(shù)名后加上小括號(hào),如果有必要需要在括號(hào)內(nèi)寫上參數(shù)
  3. 調(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ù)加括號(hào),那么 callable 判斷的就是函數(shù)的返回值是否可以執(zhí)行了
In : callable(abs)     
Out: True

# 字符串是不可調(diào)用的
In : a = '123'
In : callable(a)    
Out: False

3. 函數(shù)的參數(shù)

??定義函數(shù)的時(shí)候,括號(hào)中指定的就是函數(shù)的參數(shù) (形式參數(shù)),當(dāng)我們調(diào)用函數(shù)時(shí),需要將數(shù)據(jù)進(jìn)行傳遞,這種傳遞參數(shù)的方式就叫做傳參,嚴(yán)格來說函數(shù)只可以使用兩種方式:位置傳參關(guān)鍵字傳參

  1. 位置傳參:按照參數(shù)定義順序傳入實(shí)參,位置參數(shù)是按位置對應(yīng)的
  2. 關(guān)鍵字傳參:使用形參的名字來傳入實(shí)參的方式,如果使用了 形參的名字,那么傳入?yún)?shù)的順序就可以和定義的順序不同
  3. 當(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ù)就使用指定的 缺省值,否則 將會(huì)使用 傳遞的值。

參數(shù)缺省值也屬于位置參數(shù),只不過是給位置參數(shù)定義了默認(rèn)值。

In : def function(x = 10, y = 20):
...:     return x + y
...:

# 2 會(huì)以位置參數(shù)的形式傳遞給 x,y 沒有傳遞,會(huì)使用缺省值
In : function(2)   
Out: 22

# x 沒有傳遞,會(huì)使用缺省值
In : function(y=100)  
Out: 110

# y 沒有傳遞,會(huì)使用缺省值
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. 可變位置傳參

??在形參前使用 * 號(hào),表示該形參是可變參數(shù),可以接受多個(gè)實(shí)參,在函數(shù)內(nèi)部,可變參數(shù)會(huì)封裝成元組 (即便是沒有傳遞)

In : def function(*nums):
...:     print(nums)
...:

In : function(1,2,3,4)  # 多個(gè)參數(shù)會(huì)被 nums 收集
(1, 2, 3, 4)

In : function([1,2,3,4])  # 會(huì)把 list 收集成元組內(nèi)的一個(gè)元素
([1, 2, 3, 4],)

在函數(shù)定義時(shí),一般的規(guī)范是使用 *args, 表示收集多個(gè)位置傳參。

3.2.2. 可變關(guān)鍵字傳參

??在形參前使用 ** 號(hào),表示該形參是可變關(guān)鍵字參數(shù),可以接受多個(gè)關(guān)鍵字參數(shù),在函數(shù)內(nèi)部,可變關(guān)鍵字參數(shù)會(huì)封裝成字典 (即便是沒有傳遞)

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è)星號(hào) *
  • 可變關(guān)鍵字參數(shù)在形參前使用 兩個(gè)星號(hào) **
  • 可變位置參數(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è)星號(hào)參數(shù) (可變位置參數(shù)) 后,出現(xiàn)的普通參數(shù),我們稱它為 keyword-only 參數(shù),因?yàn)槎嘤嗟奈恢脜?shù)都會(huì)被 *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)?

  1. 給函數(shù)提供實(shí)參的時(shí)候,可以在集合類型前使用 * 或者 **,把集合類型的結(jié)構(gòu)解開,提取出其中所有元素作為函數(shù)的實(shí)參
  2. 非字典類型使用 * 解構(gòu)成位置參數(shù)
  3. 字典型使用 ** 解構(gòu)成關(guān)鍵字參數(shù)
  4. 提取出來的元素?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é):

  1. Python 函數(shù)使用 return 語句返回 "返回值"
  2. 所有函數(shù)都有返回值,如果沒有 return 語句,隱式調(diào)用return None
  3. return 語句并不一定是函數(shù)的語句塊的最后一條語句
  4. 一個(gè)函數(shù)可以存在多個(gè) return 語句,但是只有一條可以被執(zhí)行,如果沒有一條 return 語句被執(zhí)行,隱式調(diào)用return None
    5.return None 可以簡寫為 return
  5. 函數(shù)執(zhí)行到 return 就會(huì)返回,所以 return 后面的語句永遠(yuǎn)不會(huì)被執(zhí)行
  6. return 可以理解為,結(jié)束當(dāng)前函數(shù)計(jì)算,返回值!

函數(shù)永遠(yuǎn)只能返回一個(gè)數(shù)據(jù)。

  1. 返回值數(shù)量 = 0,即 return(或者不寫 return 語句),返回的數(shù)據(jù)為 None。
  2. 返回值數(shù)量 = 1,返回 object(一個(gè)對象)。
  3. 返回值數(shù)量 > 1,返回 tuple(一個(gè)元組)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容