1. 理解 * 和 **
Python的賦值陳述句可以解包將可迭代元素剝離出來
In [6]: a, b, c = [1, 2, 3]
In [7]: a
Out[7]: 1
In [8]: b
Out[8]: 2
In [9]: c
Out[9]: 3
賦值陳述句可以理解為 a, b, c = [a, b, c] = [1, 2, 3], 將變數a, b, c與目標串列中的資料進行對應.
Python中 * 和 ** 可以理解成一個特殊的解包語法. 將可迭代的物件(串列字典等)解包, 獲取其中的內容.

將 * 應用到賦值陳述句中, 可以解包多個資料對應到一個串列變數.
In [10]: a, *other = [1, 2, 3, 4]
In [11]: a
Out[11]: 1
In [12]: other
Out[12]: [2, 3, 4]
In [13]: a, *middle, x = [1, 2, 3, 4]
In [14]: middle
Out[14]: [2, 3]
結合 print 函式理解解包, 第二個print(*['a', 'b', 'c', 'd']) 使用*號將串列解包后, 相當于print('a', 'b', 'c', 'd')
In [15]: print(['a', 'b', 'c', 'd'])
['a', 'b', 'c', 'd']
In [16]: print(*['a', 'b', 'c', 'd'])
a b c d
2.Python函式的引數
Python函式的傳參, 支持兩種方式, 一種是基于位置傳遞(Positional Arguments), 一種是基于變數名稱傳遞(Keyword Arguments).
比如定義一個函式func 接受4個引數
In [1]: def func(a, b, c, d):
...: print(a, b, c, d)
可以基于位置傳參, (1, 2, 3, 4)根據位置順序分別賦值給引數a, b, c, d.
In [2]: func(1, 2, 3, 4)
1 2 3 4
也可以基于變數名傳遞引數, 指定(d=1, c=2, b=3, a=4)分別賦值給對應變數, keyword argument可以亂序
In [3]: func(d=1, c=2, b=3, a=4)
4 3 2 1
或者混合兩種引數格式, 組合位置引數和關鍵字引數. 注意這時不能重復賦值, 即已經傳遞了位置引數, 不能再通過關鍵字傳參.
如下面代碼中func(1, 2, a=3, c=4) 已經通過position引數給a賦值為1, 后面再傳keyword引數a=3的話, 對a引數賦值2次, 報TypeError
In [4]: func(1, 2, d=3, c=4)
1 2 4 3
In [5]: func(1, 2, a=3, c=4)
TypeError: func() got multiple values for argument 'a'
3. 支持任意引數的函式 *args, **kwargs
然后就是我們查看原始碼時經常看到的語法, *args, **kwargs. 可以看到arg和kwarg即是一個變數, 目的是保存函式中的位置引數和關鍵字引數,成一個元組和欄位物件, 保存args和kwargs就是變數名.
In [1]: def func(var, *args, key=None, **kwargs):
...: print('args: ', args)
...: print('kwargs: ', kwargs)
定義一個除了位置引數 var , 和關鍵字引數 key 之外還接受任意引數的函式.
呼叫函式時,傳的其他引數就會賦值給 args, 和 kwargs.

In [2]: func('one', 'two', 'three', key='key', four=4, five=5)
args: ('two', 'three')
kwargs: {'four': 4, 'five': 5}
In [3]: func('one', 'two', key='key', three='three', four=4, five=5)
args: ('two',)
kwargs: {'three': 'three', 'four': 4, 'five': 5}
可以看到 'one' 賦值給了變數 var, 'two' 和 'three' 傳給了元組args, 'key'賦值給了變數 four=4, five=5, 傳遞給了kwargs , {'four': 4, 'five': 5}.
改變three的傳參方式使用three='three'之后, three也去了kwargs.
4. 固定位置引數和關鍵字引數 / *
Python3.8 中增加了固定引數的關鍵字 / 和 * , 使用/之前的引數,只能通過位置方式傳參, 使用*之后的引數, 只能通過關鍵字方式傳參.
重新寫一個最開始的函式
In [1]: def func(a, /, b, *, c, d):
...: print(a, b, c, d)
其中引數a只能通過位置傳遞, c和d只能通過關鍵字傳遞, 引數b不做限制

In [2]: func(1, 2, c=3, d=4)
1 2 3 4
In [3]: func(1, b=2, c=3, d=4)
1 2 3 4
In [4]: func(a=1, b=2, c=3, d=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() got some positional-only arguments passed as keyword arguments: 'a'
In [5]: func(1, 2, 3, d=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() takes 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given
可以看到, 限制了引數型別之后, 傳參方式錯誤函式會報TypeError, 應用到一些需要限制顯式傳遞引數的場景, 可以提高代碼的可讀性.
5. **的另一個用法, 字典合并
Python3.8之后還增加了一個**的新用法, 支持在字典初始化時使用**語法. 合并現有字典的資料時, 可不使用dict.update()函式. 代碼示例如下
In [1]: a = {'k': 1, 'm': 2}
In [2]: y = {'y': '3', 'z': 'ii'}
In [3]: {**a}
Out[3]: {'k': 1, 'm': 2}
In [4]: {**a, **y}
Out[4]: {'k': 1, 'm': 2, 'y': '3', 'z': 'ii'}
In [5]: {**a, **y, 'uu': 88}
Out[5]: {'k': 1, 'm': 2, 'y': '3', 'z': 'ii', 'uu': 88}
總結:
本文總結了python中*和**的使用方法, 解包時可以獲取可迭代物件中的內容.
- * 和**在定義函式時使用, 使得函式可以支持任意長度的引數
- 解包時可將任意長度資料賦值給一個物件
- 關鍵字 / 和 * 規定引數的傳遞方式.
- 生成新的字典時使用**解包其他字典中的值
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/292045.html
標籤:python
