iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0

今天來介紹我常常搞不清楚的 *args

先來回憶一下我們昨天學到的 iterable unpacking:

a, b, *c = 10, 20, 'a', 'b'
print(a, b)
10 20
print(c)
['a', 'b']

可以看到 c 將 'a', 'b' 兩個元素 unpacking 在陣列中。

我們可以利用同樣的概念,放在 funciton 的引數中:

def func1(a, b, *args):
    print(a)
    print(b)
    print(args)
func1(1, 2, 'a', 'b')
1
2
('a', 'b')

這裡有幾件事值得注意:

  1. 與 iterable unpacking 不同, *args 會是 tuple 而不是 list.

  2. 參數名稱 args 是一種傳統命名,實際上你可以取名 *a, *b, ...,只是別人大概會看不懂。

  3. *args 參數之後你就不能再使用位置引數——用下去會有其他效果,我們明天解釋。

def func1(a, b, *my_vars):
    print(a)
    print(b)
    print(my_vars)
func1(10, 20, 'a', 'b', 'c')
10
20
('a', 'b', 'c')
def func1(a, b, *c, d):
    print(a)
    print(b)
    print(c)
    print(d)
func1(10, 20, 'a', 'b', 100)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

/Users/maotingyang/Downloads/star-args.ipynb Cell 14 in <cell line: 1>()
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/star-args.ipynb#X16sZmlsZQ%3D%3D?line=0'>1</a> func1(10, 20, 'a', 'b', 100)


TypeError: func1() missing 1 required keyword-only argument: 'd'

我們來設計一個計算平均數的 function:

def avg(*args):
    count = len(args)
    total = sum(args)
    return total/count
avg(2, 2, 4, 4)
3.0

But watch what happens here:

avg()
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

/Users/maotingyang/Downloads/star-args.ipynb Cell 19 in <cell line: 1>()
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/star-args.ipynb#X24sZmlsZQ%3D%3D?line=0'>1</a> avg()


/Users/maotingyang/Downloads/star-args.ipynb Cell 19 in avg(*args)
      <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/star-args.ipynb#X24sZmlsZQ%3D%3D?line=1'>2</a> count = len(args)
      <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/star-args.ipynb#X24sZmlsZQ%3D%3D?line=2'>3</a> total = sum(args)
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/star-args.ipynb#X24sZmlsZQ%3D%3D?line=3'>4</a> return total/count


ZeroDivisionError: division by zero

因為我們沒傳任何引數進去,出現分母為零的錯誤。

可以用兩種方式修改:

def avg(*args):
    count = len(args)
    total = sum(args)
    if count == 0:
        return 0
    else:
        return total/count
avg(2, 2, 4, 4)
3.0
avg()
0

上面是一種解法。

另一種解法是我們設定一個必填的參數 a,所以沒傳入任何引數時就會出錯:

def avg(a, *args):
    count = len(args) + 1
    total = a + sum(args)
    return total/count
avg(2, 2, 4, 4)
3.0
avg()
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

/Users/maotingyang/Downloads/star-args.ipynb Cell 27 in <cell line: 1>()
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/star-args.ipynb#X35sZmlsZQ%3D%3D?line=0'>1</a> avg()


TypeError: avg() missing 1 required positional argument: 'a'

我覺得第二種方法比較聰明,你呢?

Unpacking an iterable into positional arguments

def func1(a, b, c):
    print(a)
    print(b)
    print(c)
l = [10, 20, 30]

下面這種 unpacking 方式會失敗:

func1(l)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

/Users/maotingyang/Downloads/star-args.ipynb Cell 33 in <cell line: 1>()
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/star-args.ipynb#X44sZmlsZQ%3D%3D?line=0'>1</a> func1(l)


TypeError: func1() missing 2 required positional arguments: 'b' and 'c'

Python 把 l 陣列當作第一個引數,少了剩餘的引數而出錯。

我們可以利用星號 unpacking :

*l,
(10, 20, 30)
func1(*l)
10
20
30

話說混用位置引數和關鍵字引數會如何呢?

def func1(a, b, c, *d):
    print(a)
    print(b)
    print(c)
    print(d)
func1(10, c=20, b=10, 'a', 'b')
  Input In [22]
    func1(10, c=20, b=10, 'a', 'b')
                                  ^
SyntaxError: positional argument follows keyword argument

記得之前學到的嗎?一旦在函式傳入關鍵字引數,後面就不能再傳入位置引數了。

明天我們會學到如何解決這個問題,我們明天見!

參考:Python 3: Deep Dive (Part 1 - Functional)


上一篇
Extended Unpacking
下一篇
Keyword Arguments
系列文
小青蛇變大蟒蛇——進階Python學起來!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言