&>&> Aniki(a)[{"a"..." />

Python函數中*和**的內涵究竟是什麼呢?

自己隨意寫了幾行,運行了一下發現有些神奇:

&>&>&> def Aniki(a,*b,**c):

z=[a,b,c]

return z

&>&>&> a={"a":"Ass","b":"We","c":"Can"}

&>&>&> Aniki(a)

[{"a": "Ass", "b": "We", "c": "Can"}, (), {}]

&>&>&> Aniki(*a)

["a", ("b", "c"), {}]

&>&>&> Aniki(**a)

["Ass", (), {"b": "We", "c": "Can"}]

第二種情況Aniki(*a)只取了字典的key,而最後一個Aniki(**a)為何沒有把字典中"b":2賦值給b呢?

而當我再打一段,

&>&>&> Aniki(**a,b=(1,2))

Traceback (most recent call last):

File "&

", line 1, in &

Aniki(**a,b=(1,2))

TypeError: Aniki() got multiple values for keyword argument "b"

發現其實Aniki(**a)時已經給b賦了()值,無法再賦值。

想知道*和**究竟是怎麼一回事,其原理是什麼,哪裡有相對權威一點的解釋呢?


Python的參數解析比較複雜,除了源碼並沒有很好的文檔來介紹每個細節,不過我覺得language doc里已經能解決題中的疑問了,也能滿足題主權威的要求。

6. Expressions - Python 3.6.4 documentationdocs.python.org

不過我覺得鏈接中的部分沒有講清楚的就是*args和**kwargs(函數定義時的名字)是不參與運行時函數參數的名字解析的(但這並不意味著可以與位置參數和關鍵字參數重名),也是為什麼題中第一個問題b並沒有被賦值的原因。

&>&>&> def func1(a):
... pass
...
&>&>&> def func2(*a):
... pass
...
&>&>&> func1(a=1)
&>&>&> func2(a=1)
Traceback (most recent call last):
File "&", line 1, in &
TypeError: func2() got an unexpected keyword argument "a"


這個問題基本弄清楚了,星號(asterisk)主要在函數定義和函數調用的時候使用。

  1. 函數定義時
    1. 使用單個*會將所有的參數,放入一個元組(tuple)供函數使用。
    2. 使用兩個 **會將所有的關鍵字參數,放入一個字典(dict)供函數使用。
  2. 函數調用時
    1. 在list,tuple,set前加一個星號會把容器中的所有元素解包(unpack)變成位置參數。
    2. 在dict前加一個星號會把字典的鍵變成位置參數。
    3. 在dict前加兩個星號會把字典的鍵值對變成關鍵字參數。

      a={"a":"Ass","b":"We","c":"Can"}

具體到描述中的函數:

Aniki(*a)

等同於Aniki("a", "b", "c")

Aniki(**a)

等同於 Aniki(a="Ass", b="We", c="Can")

Aniki(**a,b=(1,2))

等同於 Aniki(a="Ass", b="We", c="Can",b=(1,2))

希望說清楚了。

Stack Overflow上這個問題的回答更全面,提到了星號的其他作用,推薦看一看What does ** (double star/asterisk) and * (star/asterisk) do for parameters?


Python3中新增的兩種用法:

  1. Keyword-Only Arguments 僅關鍵字參數
  2. Extended Iterable Unpacking 擴展迭代解包

僅關鍵字參數

*args後加入關鍵字參數,就可以要求這個參數必須以關鍵字的方式賦值。

def keyword_only(a, *args, b):
print[a, args, b]

在調用的時候,必須用關鍵字的方式賦值。單個星號*也有相同作用,只不過不能接收無限位置參數了。

def keyword_only(a, *, b):
print[a, args, b]

擴展迭代解包

許多演算法要求以第一個元素剩下的全部 這種方式分割一個序列。即

first, rest = seq[0], seq[1:]

現在可以這樣:

first, *rest = seq

或者這樣:

a, *b, c = seq

a取得第一個元素,c取得最後一個元素,b取得剩下的全部。

PEP文檔:

  1. PEP 3102 -- Keyword-Only Arguments
  2. PEP 3132 -- Extended Iterable Unpacking

可以用這個在線的Python3解釋器試一試,Online Python3 Compiler - Online Python3 Editor - Online Python3 IDE - Python3 Coding Online - Practice Python3 Online - Execute Python3 Online - Compile Python3 Online - Run Python3 Online


給參數去括弧


推薦閱讀:

對於初學者應該選擇python什麼版本呢?
雲伺服器上如何運行python程序?
為什麼Python第三方庫的document看起來很統一?
Python現在用3.X的好不好?2.X我在win10打開不了IDLE又是什麼問題?

TAG:Python | Python3x | Python入門 |