詳解Python函數參數定義及傳參(必備參數、關鍵字參數、默認可省略參數、可變不定長參數、*args、**kwargs)
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
這也是我們希望得到的正確結果。
下面我們把上述代碼最后一行調用的前兩個參數("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還給大家一種傳遞方式,同樣是上面的函數,可以不用按順序傳參,請看下節“必備參數__鍵值對傳參”。
必備參數__鍵值對傳參(關鍵字參數)
同樣是必備參數,但是在代用函數傳參的時候,可以直接使用鍵值對的方式,看下面演示代碼:
#!/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')
控制台輸出:
host: 127.0.0.1
port: 3306
user: root
pw: 1234
db: tests
charset: utf8
函數定義還是與上例一樣,只是調用函數的時候,參數傳遞使用了鍵值對,鍵名就是參數定義時的變量名,這樣就可以不用理會順序,只要記住鍵名(參數變量名)就可以了。
但是這畢竟是必備參數,所有的參數都要傳遞,否則會報錯,例如將調用修改成:
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中函數的不同類型參數的區別及應用場景例舉,一點心得體會,希望對有興趣的朋友能有所幫助!