本文源代碼:https://gitee.com/obullxl/PythonCS/tree/master/CS-CY2405 Python中*和**很常見 禪師在閱讀Python代碼過程中,經常看到一個函數或方法的入參是*args和**kwargs(如:def func(*args, **kwarg ...
本文源代碼:https://gitee.com/obullxl/PythonCS/tree/master/CS-CY2405
Python中*和**很常見
禪師在閱讀Python代碼過程中,經常看到一個函數或方法的入參是*args
和**kwargs
(如:def func(*args, **kwargs)
等)形式,或者在調用函數或方法時,在入參的元組和列表前面增加1個*
號(如:func(*(1, 2, 3))
等),或者在字典類型入參前面增加2個*
號(如:func(**{'x':1, 'y':2, 'z':3})
等)。
剛開始看到參數前面*
號,禪師一度以為是C/C++中的指針,但在萬物皆對象的Python種,指針是不會存在的。本文我們一起來看看1個*
號和2個**
號的含義和用法,也讓我們來感受一下Python靈活性有多強大。
位置參數和命名參數
在瞭解函數入參*args
和**kwargs
之前,我們首先要瞭解一下函數或方法的位置參數和命名參數,以函數定義def func(a, b, c, x=None, y=None, z=None)
為例:
-
位置參數通俗的講就是參數的位置的固定的,與函數或方法的參數名無關,比如函數或方法的第1個參數、第2個參數等。樣例函數的a/b/c入參就是位置參數,他們分別在函數的第1到第3個參數。Python語法規定,位置參數只能在函數或方法前面的參數(即中間不能有位置參數)。
-
命名參數通俗的講就是參數是有名字,在調用函數或方法時,需要指定參數的名稱,命名參數可以有預設值。樣例函數的x/y/z入參就是命名參數,x/y/z就是參數的名稱,且他們均有None預設值。Python語法規定,位置參數只能在函數或方法後面的參數(即中間不能有位置參數)。
1個*和2個**的作用
其實從函數入參能看出來,1個*
是位置參數,2個**
是命名參數,那麼它們到底有什麼作用呢:
-
函數或方法的定義,如
def func(*args, **kwargs)
:1個*
的作用是收集調用本函數的所有的位置參數,收集後的類型是元組;2個**
的作用也是參數收集,只是收集的是命名參數,收集後的結果是字典(在Java中稱為Map)。 -
函數或方法的調用,如
func(*(1, 2, 3), **{x=4, y=5, z=6}
):*
的作用是拆解,與收集相反;其中,1個*
為把元組或列表按照順序拆開,作為位置入參,2個**
則把字典按照命名參數拆開。
例:定義函數或方法(參數收集)
def mfunc(*args, **kwargs):
'''
函數定義:收集參數,*把所有的位置參數收集到一個元組中,**則把最後的命名參數組裝成Map字典。
'''
print(f'{type(args)} args = {args}')
print(f'{type(kwargs)} kwargs = {kwargs}')
mfunc()
mfunc(1, 2, 3, x='a', y='b')
mfunc(1, 2, ('t1', 't2'), ['t1', 't2'], {'k1': 'v1', 'k2': 'v2'}, x='a', y='b')
'''
入參拆解參數,定義收集參數,相互抵消,無實際意義。
'''
mfunc(*(1, 2, 3), **{'k1': 'v1', 'k2': 'v2'})
例:調用函數或方法(拆解或映射)
def mprint(x, y):
'''
函數調用:拆解參數,*把元組或列表按照順序拆開,作為入參,**則把Map字典按照命名參數拆開。
'''
print(f'{type(x)} x = {x}')
print(f'{type(y)} y = {y}')
mprint(*(1, 2))
mprint(*((1, 2), 3))
mprint(**{'x': 'x1', 'y': 'y1'})
特別註意:拆解位置參數數量需要與函數或方式定義一致,或者拆解命名參數的參數名需要與定義一致!
禪定:Python為什麼需要*和**?
從前面的分析可以看出*
和**
的作用和用法,Python中它們是必須的嗎?禪師答案:
- 函數和方法定義中是必須的:舉個反射的簡單場景,函數入參的個數、類型是動態的,因此需要收集(如:Java中為
Object[]
數組)
函數和方法調用是可選的,目的是為了簡化編程(Python之禪:Beautifulis better than ugly.),不需要手工逐個參數設置,如調用函數入參func(*my_lsit, **my_dict)
就明顯比func(my_list[0], my_list[1], my_list[2], my_dict['x'], my_dict['y'], my_dict['z'])
優雅太多了。
我的本博客原地址:https://ntopic.cn/p/2024050201
本文作者:奔跑的蝸牛,轉載請註明原文鏈接:https://ntopic.cn