Python: 函數參數魔法

hgfh8808 8年前發布 | 11K 次閱讀 Python Python開發

在 Python 中,定義函數和調用函數都很簡單,但如何定義函數參數和傳遞函數參數,則涉及到一些套路了。總的來說,Python 的函數參數主要分為以下幾種:

  • 必選參數
  • 默認參數
  • 可變參數
  • 關鍵字參數

必選參數

必選參數可以說是最常見的了,顧名思義,必選參數就是在調用函數的時候要傳入數量一致的參數,比如:

>>> defadd(x, y):        # x, y 是必選參數
...    print x + y
...
>>> add()                # 啥都沒傳,不行
Traceback (mostrecentcalllast):
  File "", line 1, in 
TypeError: add() takesexactly 2 arguments (0 given)
>>> add(1)                # 只傳了一個,也不行
Traceback (mostrecentcalllast):
  File "", line 1, in 
TypeError: add() takesexactly 2 arguments (1 given)
>>> add(1, 2)            # 數量一致,通過
3

默認參數

默認參數是指在定義函數的時候提供一些默認值,如果在調用函數的時候沒有傳遞該參數,則自動使用默認值,否則使用傳遞時該參數的值。

看看例子就明白了:

>>> defadd(x, y, z=1):    # x, y 是必選參數,z 是默認參數,默認值是 1
...    print x + y + z
...
>>> add(1, 2, 3)            # 1+2+3
6
>>> add(1, 2)              # 沒有傳遞 z,自動使用 z=1,即 1+2+1
4

可以看到,默認參數使用起來也很簡單,但有兩點需要注意的是:

  • 默認參數要放在所有必選參數的后面
  • 默認參數應該使用不可變對象

比如,下面對默認參數的使用是錯誤的:

>>> def add(x=1, y, z):      # x 是默認參數,必須放在所有必選參數的后面
...    return x + y + z
...
  File "<stdin>", line 1
SyntaxError: non-defaultargumentfollowsdefaultargument
>>>
>>> def add(x, y=1, z):      # y 是默認參數,必須放在所有必選參數的后面
...    return x + y + z
...
  File "<stdin>", line 1
SyntaxError: non-defaultargumentfollowsdefaultargument

再來看看為什么默認參數應該使用不可變對象。

我們看一個例子:

>>> defadd_to_list(L=[]):
...    L.append('END')
...    return L

在上面的函數中,L 是一個默認參數,默認值是 [] ,表示空列表。

我們來看看使用:

>>> add_to_list([1, 2, 3])          # 沒啥問題
[1, 2, 3, 'END']
>>> add_to_list(['a', 'b', 'c'])    # 沒啥問題
['a', 'b', 'c', 'END']
>>> add_to_list()                  # 沒有傳遞參數,使用默認值,也沒啥問題
['END']
>>> add_to_list()                  # 沒有傳遞參數,使用默認值,竟出現兩個 'END'
['END', 'END']
>>> add_to_list()                  # 糟糕了,三個 'END'
['END', 'END', 'END']

為啥呢?我們在調用函數的時候沒有傳遞參數,那么就默認使用 L=[] ,經過處理,L 應該只有一個元素,怎么會出現調用函數兩次,L 就有兩個元素呢?

原來,L 指向了可變對象 [] ,當你調用函數時,L 的內容發生了改變,默認參數的內容也會跟著變,也就是,當你第一次調用時,L 的初始值是 [] ,當你第二次調用時,L 的初始值是 ['END'] ,等等。

所以,為了避免不必要的錯誤,我們應該使用不可變對象作為函數的默認參數。

可變參數

在某些情況下,我們在定義函數的時候,無法預估函數應該制定多少個參數,這時我們就可以使用 可變參數 了,也就是,函數的參數個數是不確定的。

看看例子:

>>> defadd(*numbers):
...    sum = 0
...    for i in numbers:
...        sum += i
...    print 'numbers:', numbers
...    return sum

在上面的代碼中,numbers 就是一個可變參數,參數前面有一個 * 號,表示是可變的。在函數內部,參數 numbers 接收到的是一個 tuple。

在調用函數時,我們可以給該函數傳遞任意個參數,包括 0 個參數:

>>> add()          # 傳遞 0 個參數
numbers: ()
0
>>> add(1)          # 傳遞 1 個參數
numbers: (1,)
1
>>> add(1, 2)      # 傳遞 2 個參數
numbers: (1, 2)
3
>>> add(1, 2, 3)    # 傳遞 3 個參數
numbers: (1, 2, 3)
6

上面的 * 表示任意參數,實際上,它還有另外一個用法:用來給函數傳遞參數。

看看例子:

>>> defadd(x, y, z):        # 有 3 個必選參數
...    return x + y + z
...
>>> a = [1, 2, 3]
>>> add(a[0], a[1], a[2])    # 這樣傳遞參數很累贅
6
>>> add(*a)                  # 使用 *a,相當于上面的做法
6
>>> b = (4, 5, 6)
>>> add(*b)                  # 對元組一樣適用
15

再看一個例子:

>>> defadd(*numbers):      # 函數參數是可變參數
...    sum = 0
...    for i in numbers:
...        sum += i
...    return sum
...
>>> a = [1, 2]
>>> add(*a)                  # 使用 *a 給函數傳遞參數
3
>>> a = [1, 2, 3, 4]
>>> add(*a)
10

關鍵字參數

可變參數允許你將不定數量的參數傳遞給函數,而 關鍵字參數 則允許你將不定長度的 鍵值對 , 作為參數傳遞給一個函數。

讓我們看看例子:

>>> defadd(**kwargs):
    return kwargs
>>> add()            # 沒有參數,kwargs 為空字典
{}
>>> add(x=1)        # x=1 => kwargs={'x': 1}
{'x': 1}
>>> add(x=1, y=2)    # x=1, y=2 => kwargs={'y': 2, 'x': 1}
{'y': 2, 'x': 1}

在上面的代碼中,kwargs 就是一個關鍵字參數,它前面有兩個 * 號。kwargs 可以接收不定長度的鍵值對,在函數內部,它會表示成一個 dict。

和可變參數類似,我們也可以使用 **kwargs 的形式來調用函數,比如:

>>> defadd(x, y, z):
...    return x + y + z
...
>>> dict1 = {'z': 3, 'x': 1, 'y': 6}
>>> add(dict1['x'], dict1['y'], dict1['z'])    # 這樣傳參很累贅
10
>>> add(**dict1)        # 使用 **dict1 來傳參,等價于上面的做法
10

再看一個例子:

>>> defsum(**kwargs):              # 函數參數是關鍵字參數
...    sum = 0
...    for k, v in kwargs.items():
...        sum += v
...    return sum
>>> sum()                            # 沒有參數
0
>>> dict1 = {'x': 1}
>>> sum(**dict1)                    # 相當于 sum(x=1)
1
>>> dict2 = {'x': 2, 'y': 6} 
>>> sum(**dict2)                    # 相當于 sum(x=2, y=6)
8

參數組合

在實際的使用中,我們經常會同時用到必選參數、默認參數、可變參數和關鍵字參數或其中的某些。但是,需要注意的是, 它們在使用的時候是有順序的,依次是必選參數、默認參數、可變參數和關鍵字參數 。

比如,定義一個包含上述四種參數的函數:

>>> deffunc(x, y, z=0, *args, **kwargs):
    print 'x =', x
    print 'y =', y
    print 'z =', z
    print 'args =', args
    print 'kwargs =', kwargs

在調用函數的時候,Python 會自動按照參數位置和參數名把對應的參數傳進去。讓我們看看:

>>> func(1, 2)                    # 至少提供兩個參數,因為 x, y 是必選參數
x = 1
y = 2
z = 0
args = ()
kwargs = {}
>>> func(1, 2, 3)                  # x=1, y=2, z=3
x = 1
y = 2
z = 3
args = ()
kwargs = {}
>>> func(1, 2, 3, 4, 5, 6)        # x=1, y=2, z=3, args=(4, 5, 6), kwargs={}
x = 1
y = 2
z = 3
args = (4, 5, 6)
kwargs = {}
>>> func(1, 2, 4, u=6, v=7)        # args = (), kwargs = {'u': 6, 'v': 7}
x = 1
y = 2
z = 4
args = ()
kwargs = {'u': 6, 'v': 7}
>>> func(1, 2, 3, 4, 5, u=6, v=7)  # args = (4, 5), kwargs = {'u': 6, 'v': 7}
x = 1
y = 2
z = 3
args = (4, 5)
kwargs = {'u': 6, 'v': 7}

我們還可以通過下面的形式來傳遞參數:

>>> a = (1, 2, 3)
>>> b = {'u': 6, 'v': 7}
>>> func(*a, **b)
x = 1
y = 2
z = 3
args = ()
kwargs = {'u': 6, 'v': 7}

小結

  • 默認參數要放在所有必選參數的后面。
  • 應該使用不可變對象作為函數的默認參數。
  • *args 表示可變參數, **kwargs 表示關鍵字參數。
  • 參數組合在使用的時候是有順序的,依次是必選參數、默認參數、可變參數和關鍵字參數。
  • *args 和 **kwargs 是 Python 的慣用寫法。

參考資料

 

來自:http://python.jobbole.com/86938/

 

 本文由用戶 hgfh8808 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!