出處:http://blog.csdn.net/chenjinyu_tang/article/details/8136841
Python中*args 和**kwargs的用法
當函數的參數不確定時,可以使用*args 和**kwargs,*args 沒有key值,**kwargs有key值。
還是直接來代碼吧,廢話少說
result:
**kwargs:
result:
也可以用下面的形式:
result:
result:
出處:http://blog.csdn.net/callinglove/article/details/45483097
原文Understanding ‘*’, ‘args’,’*‘and’**kwargs’
剛開始學習Python的時候,對有關args,kwargs,和*的使用感到很困惑。相信對此感到疑惑的人也有很多。我打算通過這個帖子來排解這個疑惑(希望能減少疑惑)。
讓我們通過以下5步來理解:
1. 通過一個函數調用來理解’*’的作用
2. 通過一個函數的定義來理解’*args’的含義
3. 通過一個函數的調用來理解’**’的作用
4. 通過一個函數的定義來解’**kwargs’的含義
5. 通過一個應用實例來說明’args’,’kwargs’應用場景以及爲何要使用它
通過一個函數調用來理解’*’的作用
定義一個含三個位置參數的函數”fun”.
- 1
- 2
- 3
- 1
- 2
- 3
傳三個位置參數調用此函數
- 1
- 2
- 1
- 2
可以看到出入三個位置參數調用此函數,會打印出三個參數
現在我們定義一個含三個整數的數列,並使用’*’
- 1
- 2
- 3
- 1
- 2
- 3
‘*’ 做了什麼?
它拆開數列’l’的數值作爲位置參數,並吧這些位置參數傳給函數’fun’來調用。
因此拆數列、傳位置參數意味着fun(*l)與fun(1,2,3)是等效的,因爲l = [1,2,3]。
試着數列中使用其他數值
- 1
- 2
- 3
- 1
- 2
- 3
接下來我們試着在數列中放四個數值,調用函數會出現什麼情況呢
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
在這次調用中我們並沒有得到合適的結果,觸發了TypeWrror異常。很容易看到錯誤內容”fun() takes exactly 3 arguments (4 given)”.
爲什麼會發生這種情況呢?
數列’l’含有四個數值.因此,我們試圖調用’fun(*l)’,’l’中數值拆開傳給函數fun作爲位置參數。但是,’l’中有四個數值,調用’fun(*l)’相當於調用’fun(3,6,9,1)’,又因爲函數’fun’定義中只用三個位置參數,因此我們得到這個錯誤。同理,同樣的步驟,數列’l’中有兩個數值情況,注意error內容。
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
‘*l’與位置參數混合使用
- 1
- 2
- 1
- 2
在這裏,我們給出一個位置參數23,和從數列’l’拆除的兩個數值7和4,因此三個參數23,7和4傳給了函數’fun’
通過一個函數的定義來理解’*args’的含義
修改函數的定義:
- 1
- 2
- 3
- 1
- 2
- 3
傳一個位置參數調用此函數
- 1
- 2
- 1
- 2
傳多個參數調用此函數
- 1
- 2
- 1
- 2
‘*args’在函數定義中是做什麼用的?
它接收元組作爲位置參數,而非是常見的參數列表。在這裏,”args”是個元組。在我們解釋中不要擔心”常見的參數”這部分的理解,這個會在接下來的例子中逐漸明瞭。在上個例子中,調用函數打印”args”時,他會打印元組中包含的所有數值。
我們重新定義函數,”*args”與”常規參數列表”混合使用
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
在這個函數定義中,參數”a”代表”常規參數列表”。
傳四個位置參數調用此函數:
- 1
- 2
- 3
- 1
- 2
- 3
很容易看到,’a’打印出爲11,即第一個位置參數。’a’之後只一個參數’*args’.因此,’args’接收除常規參數之外的位置參數作爲元組。因此元組args作爲元組接收12,34和43。
我們也可以傳一個位置參數來調用此函數:
- 1
- 2
- 3
- 1
- 2
- 3
在這裏,我們傳的唯一一個參數分配給了常規參數’a’.因此,’args’接收到一個空元組。
既然我們獲取了”args”,我們可以提取需要的數值來做我們想做的事情。重新定義”fun”:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
現在我們傳任意個參數來調用此函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
‘args’既然是元組,我們就可以遍歷它。
現在我們考慮使用所有能得到的參數的場景。我們需要使用兩個函數,第一個函數帶有任意個參數,並通過另外一個函數計算除第一參數的其他參數之和。奇怪的用例,但我們只需回顧我們目前所做的。我們的目的就是在一個函數中獲取可變參數,並把這些參數餐給另一個函數。
第一步我們寫一個函數計算和。在這個用例中,這個函數會在第一個函數中應用。
- 1
- 2
- 3
- 1
- 2
- 3
在這個函數中,我們使用內建函數’sum’,它使用元組或數列作爲參數,返回元組所有元素的和。從函數的定義可以看出’args’接收包含傳給此函數位置參數的元組.因此,’args’是一個元組,簡介的作爲函數’sum’的參數。接下來定義另外一個函數,該函數有任意個參數,並利用上一個函數來計算除第一個參數之外的其他參數的和。
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
我們可以傳任意個參數給這個函數。第一個參數被常規參數’a’接收,其他參數被’iargs’作爲元組接收。正如我們考慮的案例,計算除第一個參數之外的其他參數的和。因此,我們用’a’接收第一個參數,’iargs’是包含其他參數的元組。我們用到函數’calculate_sum’,但’calculate_sum’需要多個位置參數作爲元組傳給’args’。所以在函數’ignore_first_calculate_sum’需要拆元組’iargs’,然後將元素作爲位置參數傳給’calculate_sum’.注意,用’*’拆元組。
所以,我們這樣調用’required_sum=calculate_sum(*iargs)’.
‘required_sum=calculate_sum(iargs)’不能這麼調用,因爲傳給’calculate_sum’之前我們需要unpack數值。不使用’*’將不會unpack數值,也就不能執行想要的動作。調用函數如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
得到想要的結果。
通過一個函數的調用來理解’**’的作用
定義一個三個參數的函數,並用多種方式調用:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
使用”**”調用函數,這種方式我們需要一個字典.注意:在函數調用中使用”*”,我們需要元組;在函數調用中使用”**”,我們需要一個字典
- 1
- 2
- 3
- 1
- 2
- 3
在函數調用中”**”做了什麼?
它unpack字典,並將字典中的數據項作爲鍵值參數傳給函數。因此,”fun(1, **d)”的寫法與”fun(1, b=5, c=7)”等效.
爲了更好的理解再多舉幾個例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
讓我們製造一些錯誤:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
這次調用等同於’fun(a=7, b=3, c=8, d=90)’,但函數只需要三個參數,因此我們得到TypeError
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
fun(**d)等同於fun(a=7, b=3, d=90).傳給函數”fun”想要的參數個數,但參數列表中並沒有’d’,調用中’d’鍵值參數傳給函數導致TypeError.
So, “*” unpacks the dictionary i.e the key values pairs in the dictionary as keyword arguments and these are sent as keyword arguments to the function being called. “” unpacks a list/tuple i.e the values in the list as positional arguments and these are sent as positional arguments to the function being called.
通過函數定義來理解’**kwargs’的含義
重定義函數”fun”:
- 1
- 2
- 3
- 1
- 2
- 3
此函數只用一個位置參數,因爲常規參數列表中只有一個變量’a’.但是通過”**kwargs”,可以傳多個鍵值參數。
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
在函數定義中”**kwargs”意味着什麼?
用”**kwargs”定義函數,kwargs接收除常規參數列表職位的鍵值參數字典。在這裏’kwargs’是個字典。
重新定義函數:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
錯誤調用:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
上面的調用,位置參數’a’和鍵值參數’b’都打印出來了。傳入的其他鍵值參數是’d’,函數需要鍵值參數’c’,並從字典’kwargs’獲取。但沒有傳入鍵值’c’,引發KeyError.如果傳入了鍵值’c’就不會引發這個錯誤
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
由於’**kwargs’在函數參數列表中,我們可以傳任意個鍵值參數。上面的調用傳入了”d”,但函數並沒用到。
另外一個錯誤:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
正如錯誤提示,函數’fun’只需要一個位置參數,卻給了兩個。儘管’kwargs’接收鍵值參數作爲一個字典,但你不能傳一個字典作爲位置參數給’kwargs’.你可以像下面那樣調用:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
在一個字典前使用”**”可以unpack字典,傳字典中的數據項作爲鍵值參數。
通過一個應用實例來說明’args’,’kwargs’應用場景以及爲何要使用它
在任何時候繼承類和重寫方法的,我們應當用到’*args’和’**kwargs’將接收到的位置參數和鍵值參數給父類方法。通過實例我們更好的理解
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
定義一個類,我們可以創建類的對象,類的對象有一個方法’save()’.假設類的對象可以通過save()方法保存到數據庫中。通過函數save()參數來決定是否在數據庫中創建一條記錄或者更新現存的記錄。
構造一個新類,類有’Model’的行爲,但我們只有檢查一些條件後纔會保存這個類的對象。這個新類繼承’Model’,重寫’Model’的’save()’
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
實際上對應的保存動作發生在’Model’的’save’方法中。所以我們調用子類的的’save()’方法而非’Model’的方法.子類ChildModel的’save()’接收任何父類save()需要的參數,並傳給父類方法。因此,子類’save()’方法參數列表中有”*args”和”**kwargs”,它們可以接收任意位置參數或鍵值參數,常規參數列表除外。
下面創建ChildModel實體並保存:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
這裏傳兼職參數給對象的save()方法。調用的是子類的save(),It received a dictionary containing the keyword argument in “kwargs”. Then it used “**” to unpack this dictionary as keyword arguments and then passed it to the superclass save(). So, superclass save() got a keyword argument ‘force_insert’ and acted accordingly.