【Python 進階語法 #8】args? kwargs? 也許可以不用完整的講清楚傳了什麼東西給 func?

前言

進階篇的語法,python 新手來說可以完全先不用碰,
(碰了可能有比較厲害,但更有可能觀念大亂),
大部分的功能只需要靠基礎篇的內容就能實現了!
建議會先把基礎的都學會再來看哦!

args, kwargs 是慣用名,使用時,我們不太會只講這個部分,會連前面的符號一起講
因此以下都請看作「*args」、「**kwargs」

小提示

因為開始講到比較細的東西,用詞上我會更小心一些,
注意以下 parameters 與 arguments 位置的差別,
雖然翻譯幾乎相同也很常混用就是…. 我自己之前也常講錯

def foo(parameters):
    pass

foo(arguments)

args 與 kwargs

python 裡面我們傳參數 (arguments) 給 function 時,
我們更仔細的看,其實在 arguments 我們就可以預先指定給傳給特定的 key,

這個順序有個嚴格的排列,必須先 args 再 kwargs

  • args: 位置參數 (不指定 key 的都必須先放在前面,且順序很重要)
  • kwargs: key word (故意分開表示 kw) arguments 關鍵字參數,只要擺比 args 後面即可。

當我們指定 keywords, 我們就可以無視順序的傳入參數給 function,
但如果我們沒有指定,就是一律按照順序

args

思考問題

請問以下會印出什麼呢?(建議先想過再往下看,如果答對了基本上就已經理解囉!)

def my_function(*args):
    for arg in args:
        print(arg)

my_function(1, 2, 3, 4) 

答案

我們所傳入所有的 args,其實如果是以 *args 的方式去接這些變數,就會依照順序。
(args 只是習慣,實際上可以替換成別的名稱)

kwargs

思考問題

請問以下會印出什麼呢?(建議先想過再往下看,如果答對了基本上就已經理解囉!)

def my_function(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

my_function(a=1, b=2, c=3) 

答案

**kwargs: 可以讓我們以 dict 的方式把所有帶有 key 的變數儲存,
一樣 kwargs 只是慣用名,不一定要用這個名字。

同時出現的 args 與 kwargs

我們從上面先分別了解兩者的功能後,當一個 function 出現類似

def func(*args, **kwargs):
    pass

表示「無論傳入任何的變數,這個 func 都能吃的進去」 (當然也先必須符合 args 在前, kwargs 在後的前提)

用途

從上面的敘述中,我們可以發現這種方式給予我們在撰寫 func 的時候有最大的彈性,
所以我們會使用與一些可能還不確定傳入內容,或本身就需要彈性的設計 (對外給客戶的 API …)

思考問題

請問以下會印出什麼呢?(建議先想過再往下看,如果答對了基本上就已經理解囉!)

def foo(*args, **kwargs):
    print(type(args))
    print(type(kwargs))

    for ele in args: 
        print(ele)
    for k, v in kwargs.items():
        print(f"{k}: {v}")

foo(1, 2, 3, a=4, b=5, c=6)

答案

進階討論:關於「*」這個符號

「*」 在 python 裡面有 unpack (展開) tuple (list 也可以) 的意思
而兩個的「**」,是可以 unpack dict

最後我的理解是

我們可以直接把「*args」,傳入 func 後,扣掉符號所剩下的 「args」當成是 tuple (list),
而直接把「**kwargs」,傳入 func 後,扣掉符號所剩下的 「kwargs」當成是 dict

這是我目前認為最容易理解的方式了。

題外話的嘗試

所以也有以下的用法:

mylist = [1, 2, 3]
print(*mylist)

會印出 1 2 3 (針對每個元素各別印出),
這段程式碼可翻譯為 print(1, 2, 3)

而我們沒辦法同樣的印出 print(**mydict)
因為這段程式碼會被翻譯為 print(a=4, b=5, c=6),
而這種帶有 keyword 的 print 本來就不能印出東西來

Reference