python中的*和**,能夠讓函數支持任意數量的參數,它們在函數定義和調用中,有着不同的目的
一. 打包參數
* 的作用:在函數定義中,收集所有的位置參數到一個新的元組,並將這個元組賦值給變量args
>>> def f(*args): print(args) >>> f() () >>> f(1) (1,) >>> f(1, 2, 3, 4) (1, 2, 3, 4) >>>
** 的作用:在函數定義中,收集關鍵字參數傳遞給一個字典,並將這個字典賦值給變量kwargs
>>> def f(**kwargs): print(kwargs) >>> f() {} >>> f(a=1, b=2) {'a': 1, 'b': 2} >>>
二. 解包參數
* 的作用:在函數調用中,* 能夠將元組或者列表解包成不同的參數
>>> def func(a, b, c, d): print(a, b, c, d) >>> args = (1, 2, 3, 4) >>> func(*args) 1 2 3 4 >>> args = [1, 2, 3, 4] >>> func(*args) 1 2 3 4
** 的作用:在函數調用中,**會以鍵/值的形式解包一個字典,使其成為獨立的關鍵字參數
>>> def func(a, b, c, d): print(a, b, c, d) >>> kwargs = {"a": 1, "b": 2, "c": 3, "d": 4} >>> func(**kwargs) 1 2 3 4
三. 注意
1. 在函數定義時,* 表示打包,在函數體內部, * 仍然表示解包(print(*args)實際上也算是調用了print函數)
>>> def foo(*args, **kwargs): print(args) #未解包參數 print(*args) #解包參數 >>> v = (1, 2, 4) >>> d = {'a':1, 'b':12} >>> foo(v, d) ((1, 2, 4), {'a': 1, 'b': 12}) (1, 2, 4) {'a': 1, 'b': 12}
2. 打包和解包並不能脫離函數而存在
表面上看並沒有什么函數,實際上是有的,用的就是format的函數調用
>>> c = {"name": 'zhang', "age": 2} >>> **c SyntaxError: invalid syntax >>> >>> "Name:{name}, Age:{age}".format(**c) 'Name:zhang, Age:2'
參考源碼中對format函數的定義
但是這個字典解包不能用print函數輸出
>>> print(**c) Traceback (most recent call last): File "<pyshell#40>", line 1, in <module> print(**c) TypeError: 'age' is an invalid keyword argument for this function >>>
因為上述字典解出來的形式是這樣的:
**c = name='zhang',age=2
而print函數只支持*args,不支持**kwargs
3. 在ddt中的應用
@ddt.data(*all_caseDatas)中,data是一個函數,調用函數的時候,參數*all_caseDatas自動將參數列表[{}, {}, {}...]解包為{},{},{}...,在def data(*values)函數中,*會自動將各個位置參數打包成新的元組({}, {}, {}...),然后@ddt.data就可以獲取每一條數據作為測試用例了
@ddt.data(*all_caseDatas) def test_my_request(self, case_data): global global_var if len(global_var) != 0 and case_data["request_data"] is not None: for key, value in global_var.items(): if case_data["request_data"].find(key) != -1: case_data["request_data"] = case_data["request_data"].replace(key, value)
四. 練習
請寫出下列代碼的運行結果
def f(str1, *args, **kwargs): print(str1, args, kwargs) l = [1, 2, 3] t = [4, 5, 6] d = {"a":7, "b":8, "c":9} f(1, 2) f(1, 2, 3, "python") f("python", a=1, b=2, c=3) print("================") f("python", l, d) f("python", *t) f("python", *l, **d) f("python", q="winning", **d) 運行結果: 1 (2,) {} 1 (2, 3, 'python') {} python () {'a': 1, 'b': 2, 'c': 3} ================ python ([1, 2, 3], {'a': 7, 'b': 8, 'c': 9}) {} python (4, 5, 6) {} python (1, 2, 3) {'a': 7, 'b': 8, 'c': 9} python () {'a': 7, 'b': 8, 'q': 'winning', 'c': 9}
需要注意的是f("python", *t)是把列表t先解包成 4, 5, 6,然后在def f(str1, *args, **kwargs):中將4, 5, 6重新打包成新的元組(4, 5, 6)再傳遞給變量args