python 中的可變參數

python 函數中常常看到函數的形參有 (*args,**kw)的形式,這個其實就是 python 中的可變參數,今天就來梳理一下,話不多說,淺顯易懂,快速上手。

所謂可變參數,就是傳入的參數個數是可變的,在寫通用框架的時候經常會用到。主要有以下幾種類型。

可變參數 *args

傳入的參數個數是不確定的,這樣的參數會被解釋成元組(tuple)傳遞給函數

def mutableParam(*args):
    print(args,type(args))

 有兩種方式調用

#第一種,直接傳入多個參數
mutableParam(1,2,3)

# 第二種,將多個參數放在列表(list)或者元組(tuple)中,用*解包
a = [1,2,3]
mutableParam(*a)

# 輸出結果爲
(1, 2, 3) <class 'tuple'>

在元組或者列表前添加 * 其實就是將它進行解包,而不是傳遞這個列表或者元組整體,如果不加 *,接受的參數個數就只有1個。

a = (1,2,3)

>>>print(a)      # (1,2,3)
>>>print(*a)     # 1,2,3

對接收的參數進行打印更容易觀察

def mutableParam(first,*args):
    print("first=",first,"args=",args,type(args))
    for arg in args:
        print(arg)

if __name__ == '__main__':
    a = (1,2,3)

    mutableParam(5,a)
    mutableParam(5,*a)
    mutableParam(5,1,2,3)  # 5 會傳遞給位置參數 first

# 輸出結果爲
first= 5 args= ((1, 2, 3),) <class 'tuple'>   # 沒有用 * 解包,(1,2,3)將作爲一個整體
(1, 2, 3)

first= 5 args= (1, 2, 3) <class 'tuple'>   
1
2
3

first= 5 args= (1, 2, 3) <class 'tuple'>
1
2
3

在這裏值得提一點的是,* 是解壓縮,zip 是壓縮。

可變關鍵字參數 **kw

可以給函數傳遞任意多個關鍵字參數,這樣的參數會被解釋成字典(dict)傳遞給函數

def mutableParam(name,**kw):
    print("name=",name,"kw=",kw)

同樣有兩種方式調用

# 直接傳入關鍵字參數
mutableParam("xiaoming",city="wuhan",sex="male")

# 先將關鍵字參數及其值保存爲字典,再用 ** 對字典解包
param = {"city":"wuhan","sex":"male"}
mutableParam("xiaoming",**param)

# 輸出的結果
name= xiaoming kw= {'city': 'wuhan', 'sex': 'male'}
name= xiaoming kw= {'city': 'wuhan', 'sex': 'male'}

注意到 ** 字典解包的一個神奇的現象

def myfun(a, b):
    print(a + b)

>>> mydict = {'a':1, 'b': 2}
>>> myfun(**mydict)
3
>>> myfun(*mydict)
ba

事實上

mydict = {'a':1, 'b': 2}

m,n = mydict
print(m,n)       # a b

for i in mydict:
    print(i)     # a 
                 # b

 字典中存的實際上是 key,等到要獲取值得時候,在通過 key 得到 value。

於是

>>> bob = {'name': 'Bob', 'age': 30}
>>> "{name}'s age is {age}".format(**bob)
"Bob's age is 30"

命名關鍵字參數 *

命名關鍵字參數限制了必須且只會接收哪些關鍵字參數,且在傳入參數時必須指定參數名,否則會報錯。命名關鍵字參數使用 * 作爲分隔符,* 後面的參數就是命名關鍵字參數。

def mutableParam(name,*,city,sex):
    print("name=",name,"city=",city,"sex=",sex)

if __name__ == '__main__':
    mutableParam("xiaoming",city="wuhan",sex="male")

    # 或者用 ** 對字典解包,關鍵字的順序沒有關係,city或者sex在前都可以
    # param = {"city":"wuhan","sex":"male"}
    # mutableParam("xiaoming",**param)

# 輸出的結果
name= xiaoming city= wuhan sex= male

但是如果沒有對命名關鍵字參數指定參數名稱,就會報錯。

def mutableParam(name,*,city,sex):
    print("name=",name,"city=",city,"sex=",sex)

if __name__ == '__main__':
    mutableParam("xiaoming","wuhan","male")

Traceback (most recent call last):
  File "C:/Users/jianqiangli/PycharmProjects/bishi/venv/Scripts/mutaParam.py", line 5, in <module>
    mutableParam("xiaoming",city="wuhan")
TypeError: mutableParam() missing 1 required keyword-only argument: 'sex'

與命名關鍵字參數有點相似的是,可變參數後的參數可以選擇是否指定關鍵字。如果制定了關鍵字,就會將實參的值傳給對應的關鍵字,如果不指定,則會將實參的值都傳給可變參數(可以理解爲貪婪獲取值)。

>>> def myfun(a, *b, c=None):
...     print(a)
...     print(b)
...     print(c)
...
>>> myfun(1, 2,3,4)
1
(2, 3, 4)
None

>>> myfun(1,2,3,c=4)
1
(2, 3)
4

其實類似於這種行爲

>>> first, *new, last = [94, 85, 73, 46]   # 這種方法可以用來實現切片同樣的效果
>>> new
[85, 73]

以上可變參數可以混合使用,但是順序應該爲:必選參數、默認參數、可變參數/命名關鍵字參數和可變關鍵字參數

def mutableParam(name, sex="male", *,city, **kw):
    print('name=',name,'sex=',sex,'city=',city,'kw=',kw)

if __name__ == '__main__':
    mutableParam("xiaoming","female",city="wuhan",habit="football")

# 輸出的結果
name= xiaoming sex= female city= wuhan kw= {'habit': 'football'}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章