在學習裝飾器的時候,裝飾函數(比如寫一個計算函數運行時間的裝飾函數)我們常常是不知道被裝飾函數會傳入多少參數的,因此在裝飾函數中,常常會使用(*args, **kargs)的方式來定義內部函數。因此我們需要了解一下*args和**kargs在函數定義和函數使用方面的不同,他們兩者被稱為可變參數傳入。
1、在函數定義時
可變參數傳入最常見的使用,就是在函數的定義時,有些函數寫出來我們並不確定函數使用者會傳入多少的參數?就會使用*args和**kargs。
1.1、可變位置參數:*args
在函數定義中使用*args,當函數在使用的時候,無論用戶傳入多少的參數都會被args用元組來儲存起來,函數內部可以對args任意操作來提取內部元素(也就是用戶的輸入參數),直接看例子。
def myfun(*args): print(type(args)) print("參數個數",len(args)) print("第一個參數:",args[0]) print("第二個參數:",args[1]) myfun(10, "我可以", [1,2])
執行結果:
可以看到我這里只輸出了2個我傳入的兩個參數,如果我只傳入1個參數,那么在代碼的第5行將會報錯,因為args元組中參數個數只有1個,無法提取args[1]。這就是函數定義時*args的用法,當然該用法也可以和指定參數一起使用,例如我在定義函數的時候def myfun(arg1, arg2, *args),那么這個時候傳入參數的第一個參數會認為arg1,第二個參數時arg2,第三個即以后的傳入的參數會被args當成元組組合。
1.2、可變關鍵字參數:**kargs
**kargs的用法和*args差不多,只不過kargs是采用字典的方式來收集傳入的參數。可能會問kargs字典的鍵和值分別是什么呢?難道必須要求我們使用函數的時候傳入一個字典進去?其實並不是,當我們使用函數時采用指定參數傳入的時候,例如myfun(arg1=xxx, arg2=xxx)的時候,其中就會被收集成{arg1:xxx,arg2:xxx},看例子。
def myfun(**kargs): print(type(kargs)) print("參數個數",len(kargs)) print("字典具有那些鍵?",kargs.keys()) ## 打印kargs的所有項 for item in kargs.items(): print("item:",item) myfun(number=10, number2=['可以1','可以2'])
執行結果:
當然了,**kargs也可以和指定參數一樣的使用,例如對上面這個例子稍微的改動下,我把myfun中指定number參數作為指定傳入參數,再來看看輸出。
def myfun(number, **kargs): print("參數number:",number) print(type(kargs)) print("參數個數",len(kargs)) print("字典具有那些鍵?",kargs.keys()) ## 打印kargs的所有項 for item in kargs.items(): print("item:",item) myfun(number=10, number2=['可以1','可以2'])
輸出結果:
這個時候kargs只把number2收錄到字典里了,number1被正常傳入了。
2、在函數使用時
前面講解了在函數定義的時候如何使用可變位置參數(可變關鍵字參數),這兩個東西在函數使用的時候又有點不太一樣。
2.1、可變位置參數:*args
在使用函數的時候,我們可以通過*元組(列表)的方式把元組(列表)中所有的元素傳入進函數里。要注意args一定要是元組(列表),並且args的個數一定要和函數需要的參數個數一樣多。看例子。
def myfun(arg1, arg2, arg3): print("參數arg1:",arg1) print("參數arg2:",arg2) print("參數arg3:",arg3) args = (1,2,3) myfun(*args)
輸出結果:
其實這種用法只是一種很簡潔的函數調用方式。
2.2、可變關鍵字參數:**kargs
同樣的我們使用**kargs可以把一個字典傳入函數,但是要注意的是這個字典的鍵(str)必須得和函數定義時的參數名對應。下面看例子。
def myfun(arg1, arg2, arg3): print("參數arg1:",arg1) print("參數arg2:",arg2) print("參數arg3:",arg3) kargs = {'arg1':1, 'arg2':2, 'arg3':"可以"} myfun(**kargs)
輸出結果: