詳解Python 函數(shù)參數(shù)的拆解
本文為閱讀 《Python Tricks: The Book》一書(shū)的 3.5 Function Argument Unpacking 的筆記與擴(kuò)充理解。函數(shù)參數(shù)拆解是定義可變參數(shù)(VarArgs) *args
和 **kwargs
的反向特性。
*args
和 **kwars
是函數(shù)可定義一個(gè)形參來(lái)接收傳入的不定數(shù)量的實(shí)參。
而這里的函數(shù)參數(shù)拆解是形參定義多個(gè),在調(diào)用時(shí)只傳入一個(gè)集合類型對(duì)象(帶上 * 或 ** 前綴),如 list
, tuple
, dict
, 甚至是 generator
, 然后函數(shù)能自動(dòng)從集合對(duì)象中取得對(duì)應(yīng)的值。
如果能理解下面賦值時(shí)的參數(shù)拆解和 Python 3.5 的新增 *
**
操作,那么于本文講述的特性就好理解了。
唯一的不同時(shí)作為參數(shù)的集合傳入函數(shù)時(shí)必須前面加上 *
或 **
, 以此宣告該參數(shù)將被拆解,而非一個(gè)整體作為一個(gè)函數(shù)參數(shù)。加上 *
或 **
與 Java 的 @SafeVarargs
有類似的功效,最接近的是 Scala 的 foo(Array[String]("d", "e") : _*)
寫法。參見(jiàn):Java 和 Scala 調(diào)用變參的方式
Python 的賦值拆解操作
>>> a, b = [1, 2] # a, b = (1, 2) 也是一樣的效果 >>> print(a, b) 1 2 >>> a, b = {'x': 1, 'y':2} >>> print(a, b) x y >>> a, b = {'x': 1, 'y':2}.keys() >>> print(a, b) x y >>> a, b = {'x': 1, 'y':2}.values() >>> print(a, b) 1 2 >>> a, b = (x * x for x in range(2)) >>> print(a, b) 0 1
Python 3.5 的新增拆解操作
>>> [1, 2, *range(3), *[4, 5], *(6, 7)] # * 號(hào)能把集合打散,flatten(unwrap) [1, 2, 0, 1, 2, 4, 5, 6, 7] >>> {'x': 1, **{'y': 2, 'z': 3}} # ** 把字典打散, flatten(unwrap) 操作 {'x': 1, 'y': 2, 'z': 3}
有些像是函數(shù)編程中的 flatten
或 unwrap
操作。
有了上面的基礎(chǔ)后,再回到原書(shū)中的例子,當(dāng)我們定義如下打印 3-D 坐標(biāo)的函數(shù)
def print_vector(x, y, z): print('<%s, %s, %s>' % (x, y, z))
依次傳入三個(gè)參數(shù)的方式就不值不提了,現(xiàn)在就看如何利用函數(shù)的參數(shù)拆解特性,只傳入一個(gè)集合參數(shù),讓該 print_vector
函數(shù)準(zhǔn)確從集合中獲得相應(yīng)的 x
, y
, 和 z
的值。
函數(shù)參數(shù)拆解的調(diào)用舉例
>>> list_vec = [2, 1, 3] >>> print_vector(*list_vec) <2, 1, 3> >>> print_vector(*(2, 1, 3)) <2, 1, 3> >>> dict_vec = {'y': 2, 'z': 1, 'x': 3} >>> print_vector(*dict_vec) # 相當(dāng)于 print_vector(*dict_vec.keys()) <y, z, x> >>> print_vector(**dict_vec) # 相當(dāng)于 print_vector(dict_vec['x'], dict_vec['y'], dict_vec['z'] <3, 2, 1> >>> genexpr = (x * x for x in range(3)) >>> print_vector(*genexpr) <0, 1, 4> >>> print_vector(*dict_vec.values()) # 即 print_vector(*list(dict_vec.values())) <2, 1, 3>
注意 **dict_vec
有點(diǎn)不一樣,它的內(nèi)容必須是函數(shù) print_vector
的形參 'x', 'y', 'z' 作為 key 的三個(gè)元素。
以下是各種錯(cuò)誤
**dict_vec
元素個(gè)數(shù)不對(duì),或 key 不匹配時(shí)的錯(cuò)誤
>>> print_vector(**{'y': 2, 'z': 1, 'x': 3}) <3, 2, 1> >>> print_vector(**{'y': 2, 'z': 1, 'a': 3}) #元素個(gè)數(shù)是3 個(gè),但出現(xiàn) x, y, z 之外的 key Traceback (most recent call last): File "<pyshell#39>", line 1, in <module> print_vector(**{'y': 2, 'z': 1, 'a': 3}) TypeError: print_vector() got an unexpected keyword argument 'a' >>> print_vector(**{'y': 2, 'z': 1, 'x': 3, 'a': 4}) # 包含有 x, y, z, 但有四個(gè)元素,key 'a' 不能識(shí)別 Traceback (most recent call last): File "<pyshell#40>", line 1, in <module> print_vector(**{'y': 2, 'z': 1, 'x': 3, 'a': 4}) TypeError: print_vector() got an unexpected keyword argument 'a' >>> print_vector(**{'y': 2, 'z': 1}) # 缺少 key 'x' 對(duì)應(yīng)的元素 Traceback (most recent call last): File "<pyshell#41>", line 1, in <module> print_vector(**{'y': 2, 'z': 1}) TypeError: print_vector() missing 1 required positional argument: 'x'
不帶星星的錯(cuò)誤
>>> print_vector([2, 1, 3]) Traceback (most recent call last): File "<pyshell#44>", line 1, in <module> print_vector([2, 1, 3]) TypeError: print_vector() missing 2 required positional arguments: 'y' and 'z'
把集合對(duì)象整體作為第一個(gè)參數(shù),所以未傳入 y 和 z,因此必須用前綴 * 或 ** 通告函數(shù)進(jìn)行參數(shù)拆解
集合長(zhǎng)度與函數(shù)參數(shù)個(gè)數(shù)不匹配時(shí)的錯(cuò)誤
>>> print_vector(*[2, 1]) # 拆成了 x=2, y=1, 然后 z 呢? Traceback (most recent call last): File "<pyshell#47>", line 1, in <module> print_vector(*[2, 1]) TypeError: print_vector() missing 1 required positional argument: 'z' >>> print_vector(*[2, 1, 3, 4]) # 雖然拆出了 x=2, y=1, z=3, 但也別想強(qiáng)塞第四個(gè)元素給該函數(shù)(只定義的三個(gè)參數(shù)) Traceback (most recent call last): File "<pyshell#48>", line 1, in <module> print_vector(*[2, 1, 3, 4]) TypeError: print_vector() takes 3 positional arguments but 4 were given
上面這兩個(gè)錯(cuò)誤與賦值時(shí)的拆解因元素個(gè)數(shù)不匹配時(shí)的錯(cuò)誤是相對(duì)應(yīng)的
>>> a, b = [1] Traceback (most recent call last): File "<pyshell#54>", line 1, in <module> a, b = [1] ValueError: not enough values to unpack (expected 2, got 1) >>> a, b = [1, 2, 3] Traceback (most recent call last): File "<pyshell#55>", line 1, in <module> a, b = [1, 2, 3] ValueError: too many values to unpack (expected 2)
當(dāng)然在賦值時(shí) Python 可以像下面那樣做
a, b, *c = [1, 2, 3, 4] >>> print(a, b, c) 1 2 [3, 4]
補(bǔ)充(2020-07-02): 迭代的拆解在 Python 中的術(shù)語(yǔ)是 Iterable Unpacking, 找到兩個(gè)相關(guān)的 PEP 448, PEP 3132。在實(shí)際上用處還是很大的,比如在拆分字符串時(shí)只關(guān)系自己有興趣的字段
line = '2020-06-19 22:14:00 2688 abc.json' date, time, size, name = line.split() # 獲得所有字段值 _, time, _, name = line.split() # 只對(duì) time 和 name 有興趣 date, *_ = line.split() # 只對(duì)第一個(gè) date 有興趣 *_, name = line.split() # 只對(duì)最后的 name 有興趣 date, *_, name = line.split() # 對(duì)兩邊的 date, name 有興趣
這樣就避免了用索引號(hào)來(lái)引用拆分后的值,如 split[0], splint[2] 等,有名的變量不容易出錯(cuò)。注意到 Python 在拆解時(shí)非常聰明,它知道怎么去對(duì)應(yīng)位置,用了星號(hào)(*) 的情況,明白如何處理前面跳過(guò)多少個(gè),中間跳過(guò)多少個(gè),或最后收集多少個(gè)元素。
鏈接:
PEP 448 -- Additional Unpacking Generalizations
PEP 3132 -- Extended Iterable Unpacking
以上就是詳解Python 函數(shù)參數(shù)的拆解的詳細(xì)內(nèi)容,更多關(guān)于python 函數(shù)參數(shù)拆解的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Django 數(shù)據(jù)庫(kù)同步操作技巧詳解
這篇文章主要介紹了Django 數(shù)據(jù)庫(kù)同步操作技巧詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07Django數(shù)據(jù)結(jié)果集序列化并展示實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了Django數(shù)據(jù)結(jié)果集序列化并展示實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Django ModelSerializer實(shí)現(xiàn)自定義驗(yàn)證的使用示例
本文主要介紹了Django ModelSerializer實(shí)現(xiàn)自定義驗(yàn)證的使用示例,多種字段驗(yàn)證器幫助開(kāi)發(fā)者確保數(shù)據(jù)的完整性和準(zhǔn)確性,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11Python?matplotlib繪制散點(diǎn)圖配置(萬(wàn)能模板案例)
這篇文章主要介紹了Python?matplotlib繪制散點(diǎn)圖配置(萬(wàn)能模板案例),散點(diǎn)圖是指在??回歸分析???中,數(shù)據(jù)點(diǎn)在直角坐標(biāo)系平面上的?分布圖???,散點(diǎn)圖表示因變量隨??自變量???而?變化???的大致趨勢(shì),據(jù)此可以選擇合適的函數(shù)??對(duì)數(shù)???據(jù)點(diǎn)進(jìn)行?擬合2022-07-07Python如何實(shí)現(xiàn)文本轉(zhuǎn)語(yǔ)音
文本轉(zhuǎn)語(yǔ)音,一般會(huì)用在無(wú)障礙開(kāi)發(fā)。下面介紹如何使用Python實(shí)現(xiàn)將文本文件轉(zhuǎn)換成語(yǔ)音輸出。跟著小編一起來(lái)看看吧。2016-08-08Python實(shí)現(xiàn)12種降維算法的示例代碼
數(shù)據(jù)降維算法是機(jī)器學(xué)習(xí)算法中的大家族,與分類、回歸、聚類等算法不同,它的目標(biāo)是將向量投影到低維空間,以達(dá)到某種目的如可視化,或是做分類。本文將利用Python實(shí)現(xiàn)12種降維算法,需要的可以參考一下2022-04-04關(guān)于Python中 循環(huán)器 itertools的介紹
循環(huán)器是對(duì)象的容器,包含有多個(gè)對(duì)象。通過(guò)調(diào)用循環(huán)器的next()方法 (__next__()方法,在Python 3.x中),循環(huán)器將依次返回一個(gè)對(duì)象。直到所有的對(duì)象遍歷窮盡,循環(huán)器將舉出StopIteration錯(cuò)誤。這篇文章將對(duì)此做一個(gè)詳細(xì)介紹,感興趣的小伙伴請(qǐng)參考下面文字內(nèi)容2021-09-09