詳解Python函數參數定義及傳參(必備參數、關鍵字參數、默承認省略參數、可變不定長參數、*args、**kwargs)

詳解Python函數參數定義及傳參(必備參數、關鍵字參數、默承認省略參數、可變不定長參數、*args、**kwargs)

Python函數參數傳參的種類

  Python中函數參數定義及調用函數時傳參大致可分必備參數、關鍵字參數、默承認省略參數、不定長元組參數、不定長關鍵字參數等,下面經過函數定義及調用上的不一樣狀況深刻解析這些中參數的不一樣及應用場景。python

  爲了更好的理解不一樣參數的具體意義,因此下面演示代碼中,使用的參數數量較多。具體是一個調用MySQL數據庫配置參數的函數所須要的參數,咱們用這個來演示不一樣類型的特色及適用方法,瞭解每種類型的應用場景及優缺點。數據庫

必備參數__僅賦值傳參
  必備參數,就是在調用函數的時候,定義的參數要所有都有賦值,不然執行的時候代碼會報錯。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用必備參數
def demo_get_conf1(user, pw, host, port, db, charset):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', user)
    print('pw: ', pw)
    print('db: ', db)
    print('charset: ', charset)


demo_get_conf1('root', '1234', '127.0.0.1', '3306', 'tests', 'utf8')

  上述代碼中,調用demo_get_conf1函數的時候,定義的全部參數都必須傳遞,而且要按照規定的順序傳遞,不然函數體內獲得的也是錯誤的。以上代碼控制檯輸出:數組

host:  127.0.0.1
port:  3306
user:  root
pw:  1234
db:  tests
charset:  utf8

  這也是咱們但願獲得的正確結果。bash

  下面咱們把上述代碼最後一行調用的前兩個參數("root"和"1234")對調一下:網絡

demo_get_conf1('1234', 'root', '127.0.0.1', '3306', 'tests', 'utf8')

  執行後控制檯輸出:函數

host:  127.0.0.1
port:  3306
user:  1234
pw:  root
db:  tests
charset:  utf8

  很顯然,獲得的 user 變成了 1234,pw 變成了 root,也就是說是徹底按照位置來對應函數定義時的參數變量,因此傳參的時候,順序不能錯,參數比較多的時候,就不容易記住順序了。那麼Python還給你們一種傳遞方式,一樣是上面的函數,能夠不用按順序傳參,請看下節「必備參數__鍵值對傳參」。ui

必備參數__鍵值對傳參(關鍵字參數)
  一樣是必備參數,可是在代用函數傳參的時候,能夠直接使用鍵值對的方式,看下面演示代碼:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用必備參數
def demo_get_conf1(user, pw, host, port, db, charset):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', user)
    print('pw: ', pw)
    print('db: ', db)
    print('charset: ', charset)


demo_get_conf1(
    charset='utf8',
    pw='1234',
    user='root',
    host='127.0.0.1',
    port='3306',
    db='tests')

  控制檯輸出:code

host:  127.0.0.1
port:  3306
user:  root
pw:  1234
db:  tests
charset:  utf8

  函數定義仍是與上例同樣,只是調用函數的時候,參數傳遞使用了鍵值對,鍵名就是參數定義時的變量名,這樣就能夠不用理會順序,只要記住鍵名(參數變量名)就能夠了。utf-8

  可是這畢竟是必備參數,全部的參數都要傳遞,不然會報錯,例如將調用修改爲:get

demo_get_conf1(
    pw='1234',
    user='root',
    host='127.0.0.1',
    port='3306',
    db='tests')

  控制檯會輸出:

TypeError: demo_get_conf1() missing 1 required positional argument: 'charset'

  提示缺乏'charset'參數,代碼不能正常運行。那麼有沒有能夠缺省參數,用就傳遞,不用就不傳遞的,Python確定也有這種參數,繼續看下一節「默承認省略參數」。

默承認省略參數

  默承認省略參數,就是在定義的時候就給了默認值,若是在函數調用的時候給這個參數傳值了,那麼就使用傳遞的值,若是沒有傳遞就使用定義時候的默認值。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用默承認省略參數
def demo_get_conf2(user, pw, host, port, db, charset='utf8'):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', user)
    print('pw: ', pw)
    print('db: ', db)
    print('charset: ', charset)


demo_get_conf2('root', '1234', '127.0.0.1', '3306', 'tests')

  在上述代碼中,調用demo_get_conf2函數的時候,咱們並無傳遞第六個參數charset,可是代碼沒有報錯,控制檯輸出:

host:  127.0.0.1
port:  3306
user:  root
pw:  1234
db:  tests
charset:  utf8

  可見參數"charset"雖然在調用的時候沒有傳遞,可是依然獲得了值"utf8",這個值就是在函數定義時候,參數"charset"賦值的默認值。

  可是這個參數必須在後面,不然調用的時候按照順序賦值的時候,少傳遞一個就不是這個有默認值的了,因此Python不容許那樣作,看下面的例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用默承認省略參數
def demo_get_conf1(user, pw, host, port, db='tests', charset):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', user)
    print('pw: ', pw)
    print('db: ', db)
    print('charset: ', charset)


demo_get_conf1('root', '1234', '127.0.0.1', '3306', 'tests')

  控制檯輸出:

SyntaxError: non-default argument follows default argument

  提示非默認參數不能在默認參數以後,代碼不能正常執行。

  有些時候,咱們不能肯定要具體傳遞幾個參數,應用場景須要的參數數量差別較大,那麼是否能夠動態傳遞不一樣數量的參數呢,繼續看下一節「可變長元組參數」

不定長元組參數(*args)
  不定長元組參數,就是不肯定數量的參數,定義一個參數把傳入的參數組合成元組,來接收函數調用時傳遞過來的N個參數,在函數體內以元組形式按順序讀取。爲了演示更可能是使用場景,下面沒有使用網絡中一般使用的循環方式來取可變長元組參數。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用可變長元組參數
def demo_get_conf3(host, port, *cnf):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', cnf[0])
    print('pw: ', cnf[1])
    print('db: ', cnf[2])
    print('charset: ', cnf[3])


demo_get_conf3('127.0.0.1', '3306', 'root', '1234', 'tests', 'utf8')

控制檯輸出:

host:  127.0.0.1
port:  3306
user:  root
pw:  1234
db:  tests
charset:  utf8

  可見這是咱們正常須要獲得的結果,能夠多傳更多的參數,只要裏面取值的數量沒有超過傳遞過來可變參數的數量,就不會報錯。

  在上例中,host 和 port 是必備參數,函數調用的時候,在這兩個參數後面所傳遞的,就都是對應到函數定義時的變長參數元組裏了。

  在Python中,函數參數是可使用元組的,那麼這總定義與直接使用元組參數有什麼區別呢,下面看使用元組參數的示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用元組參數
def demo_get_conf4(host, port, cnf):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', cnf[0])
    print('pw: ', cnf[1])
    print('db: ', cnf[2])
    print('charset: ', cnf[3])


demo_get_conf4('127.0.0.1', '3306', ('root', '1234', 'tests', 'utf8'))

  控制檯輸出:

host:  127.0.0.1
port:  3306
user:  root
pw:  1234
db:  tests
charset:  utf8

  與上一例比,函數體如出一轍,參數 cnf 只是少了個 「*」。重點是調用的時候不一樣,能夠看出明顯的區別,可變長元組參數在調用的時候,能夠與必備參數同樣依次傳遞,而定義元組類型參數,調用函數傳遞參數時,須要傳遞元組類型的數據才能夠。

  這種參數傳遞的時候,元組裏面的元素也是要強調順序的,若是是累加一類的函數,順序不重要,若是是每一個元素都表明不一樣具體含義的,那順序就十分重要,不能夠搞錯,不然與必備參數同樣,會在函數體內取值錯誤。

  在上兩例中,只能算是元組參數,還不能算不定長,由於函數體內的取值規定了元組的元素數量,那接下來看一個網絡上一般寫法的例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用可變長元組參數
def demo_get_conf5(x, y, *nums):
    "獲得累加和"
    res = x + y
    for i in nums:
        res += i
    return res


print(demo_get_conf5(10, 20,))
print(demo_get_conf5(10, 20, 15, 25, 30))
print(demo_get_conf5(10, 20, 15, 25, 30, 50, 30))

  控制檯輸出:

30
100
180

  上例中,前兩個參數是必須傳的,後面的參數可傳可不傳,傳的數量也不固定,根據須要由外部調用決定,因此這是可變長參數。可是這種應用適合元組內參數是相同類型和做用,若是回到上面的配置參數應用中,是否能夠不定長的呢,看下面的代碼:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用可變長元組參數
def demo_get_conf6(host, port, *cnf):
    "打印獲得的數據庫配置"
    arr = ['root', '1234', 'tests', 'utf8']     # 可變參數的默認值
    len_arr = len(arr)
    len_cnf = len(cnf)
    if len_cnf > len_arr:
        len_cnf = len_arr                       # 取變長參數最多不超過默認列表中的數量,多餘的忽略

    for i in range(len_cnf):
        arr[i] = cnf[i]

    print('host: ', host)
    print('port: ', port)
    print('user: ', arr[0])
    print('pw: ', arr[1])
    print('db: ', arr[2])
    print('charset: ', arr[3])


print('\n', '傳遞5個變長參數')
demo_get_conf6('127.0.0.1', '3306', 'new_user', '5678', 'tests', 'utf8mb4', 'abc')
print('\n', '傳遞4個變長參數')
demo_get_conf6('127.0.0.1', '3306', 'new_user', '5678', 'tests', 'utf8mb4')
print('\n', '傳遞2個變長參數')
demo_get_conf6('127.0.0.1', '3306', 'new_user', '5678')
print('\n', '不傳遞變長參數')
demo_get_conf6('127.0.0.1', '3306')

  控制檯輸出:

傳遞5個變長參數
host:  127.0.0.1
port:  3306
user:  new_user
pw:  5678
db:  tests
charset:  utf8mb4

 傳遞4個變長參數
host:  127.0.0.1
port:  3306
user:  new_user
pw:  5678
db:  tests
charset:  utf8mb4

 傳遞2個變長參數
host:  127.0.0.1
port:  3306
user:  new_user
pw:  5678
db:  tests
charset:  utf8

 不傳遞變長參數
host:  127.0.0.1
port:  3306
user:  root
pw:  1234
db:  tests
charset:  utf8

  能夠看出,傳遞5個變長參數的,多出那個「abc」參數被忽略掉了,餘下的四個參數都按照傳遞的值取到了;傳遞4個變長參數的,徹底吻合,獲得的都是傳遞的參數;傳遞2個變長參數的,前兩個變長參數是調用傳輸時傳遞的值,後兩個則是使用的默認值;不傳遞變長參數的,變長參數所有使用了默認值。這就實現了不一樣用途的變長參數取值並均可以設置默認值的目的,在必定範圍內實現了不定長。

  可是這種變長參數,都仍是要保證傳遞順序的,元組裏的順序若是傳遞錯誤,對於後面例子那獲取的數據就是錯誤的。是否能夠不定長有不用理會順序呢,繼續看下一節「不定長字典參數」。

不定長字典參數(**kwargs)
  不定長字典參數,就是不肯定數量的參數,定義一個字典,按鍵值對形式來接收函數調用時傳遞過來的N個參數,在函數體內以字典形式按鍵值對讀取。這樣在傳遞的時候,就能夠不用在乎順序問題了,看下面的代碼:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用可變長字典參數
def demo_get_conf7(host, port, **cnf):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', cnf['user'])
    print('pw: ', cnf['pw'])
    print('db: ', cnf['db'])
    print('charset: ', cnf['charset'])


demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678', db='tests', charset='utf8mb4')

  控制檯輸出:

host:  127.0.0.1
port:  3306
user:  new_user
pw:  5678
db:  tests
charset:  utf8mb4

  在上述代碼中,能夠看出,在函數體內實際把**cnf參數當作字典來讀取,那麼與把函數參數直接定義成字典來用相比較,對函數體內是沒有區別的,可是在函數調用的時候,參數傳遞就有差異了。若是參數定義成字典,那麼調用的時候就須要傳遞字典,不然會報錯,以下面代碼:

# 演示得到數據庫配置參數,使用字典參數
def demo_get_conf7(host, port, cnf):
    "打印獲得的數據庫配置"
    print('host: ', host)
    print('port: ', port)
    print('user: ', cnf['user'])
    print('pw: ', cnf['pw'])
    print('db: ', cnf['db'])
    print('charset: ', cnf['charset'])


demo_get_conf7('127.0.0.1', '3306', {'user':'new_user', 'pw':'5678', 'db':'tests', 'charset':'utf8mb4'})

  與上一例比,函數體如出一轍,參數 cnf 只是少了兩個 「*」。重點是調用的時候不一樣,能夠看出明顯的區別,可變長字典參數在調用的時候,能夠直接寫鍵名,不用引號,使用「=」賦值,而定義字典類型參數,調用函數傳遞參數時,須要傳遞字典類型的數據才能夠。

  在上線的例子中,函數體內的代碼變相等於指定了不定長參數**cnf的長度,但參數是能夠變長的是肯定的,主要是函數體裏面取值的代碼邏輯。若是循環打印輸出,就能夠任意變長,可是實際項目中這樣作適用場景很少。仍是取數據庫配置這個需求,咱們改寫一下函數體的代碼:

#!/usr/bin/env python
# -*- coding: utf-8 -*-


# 演示得到數據庫配置參數,使用字典參數
def demo_get_conf7(host, port, **cnf):
    "打印獲得的數據庫配置"
    arr = {'user': 'root', 'pw': '1234', 'db': 'tests', 'charset': 'utf8'}     # 可變參數的默認值

    for key, val in cnf.items():
        if key in arr:
            arr[key] = val                       # 取變長參數傳遞過來的鍵,若是在預置裏面存在就更改,不存在的忽略

    print('host: ', host)
    print('port: ', port)
    print('user: ', arr['user'])
    print('pw: ', arr['pw'])
    print('db: ', arr['db'])
    print('charset: ', arr['charset'])


print('----------參數完整傳遞:')
demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678', db='tests', charset='utf8mb4')
print('----------參數多餘傳遞:')
demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678', db='tests', charset='utf8mb4', abc='123')
print('----------參數減小傳遞:')
demo_get_conf7('127.0.0.1', '3306', user='new_user', pw='5678')
print('----------變參沒有傳遞:')
demo_get_conf7('127.0.0.1', '3306')

  控制檯輸出:

----------參數完整傳遞:
host:  127.0.0.1
port:  3306
user:  new_user
pw:  5678
db:  tests
charset:  utf8mb4
----------參數多餘傳遞:
host:  127.0.0.1
port:  3306
user:  new_user
pw:  5678
db:  tests
charset:  utf8mb4
----------參數減小傳遞:
host:  127.0.0.1
port:  3306
user:  new_user
pw:  5678
db:  tests
charset:  utf8
----------變參沒有傳遞:
host:  127.0.0.1
port:  3306
user:  root
pw:  1234
db:  tests
charset:  utf8

  從控制檯結果能夠看出,多餘傳遞的可變長參數被忽略掉了,少傳的可變長參數使用了函數體內的默認值。可變長參數若是一個也沒傳遞,那就徹底使用了函數體內的默認值。

  以上是對Python中函數的不一樣類型參數的區別及應用場景例舉,一點心得體會,但願對有興趣的朋友能有所幫助!

相關文章
相關標籤/搜索