Python 函數的參數

python 函數的參數可分爲位置參數、缺省參數、可變參數和關鍵字參數。其中可變參數和關鍵字參數又可以進行拆包。

位置參數

看下面程序:

    def fun1(a, b):
        print("a -- " + str(a))
        print("b -- " + str(b))
        return a + b

    print(fun1(2, 3))

顯然,程序結果:

    a ---- 2
    b ---- 3
    5

這裏的函數 fun1 中的參數 a 和 b 就是位置參數。位置參數在調用時,必須給到具體值。

缺省參數

看下面的代碼:

    def fun2(a, b, c=0):
        print("a -- " + str(a))
        print("b -- " + str(b))
        print("c -- " + str(c))
        return a + b + c

    print(fun2(2, 3))
    print(fun2(2, 3, 4))

程序輸出結果:

    a -- 2
    b -- 3
    c -- 0
    5
    a -- 2
    b -- 3
    c -- 4
    9

這裏函數 fun2 中,有三個參數,其中 a 和 b 是位置參數, c 即是一個缺省參數。聲明函數 fun2 時指定了參數 c=0 ,表示參數 c 的默認值是 0 ,上面程序中兩次在調用 fun2 時,分別傳入了兩個參數和三個參數。我們看到,在傳入兩個參數時,a 和 b 的值分別是傳入的 2 和 3,其中 c 的值爲默認值 0 ,在傳入三個參數時,a, b 和 c
值分別是傳入的 2, 3, 4 。
很好理解,在函數定義的時候,給參數賦了一個默認值,這樣的參數就叫缺省參數,也叫默認參數。
假設有多個缺省參數,而我只傳入了部分缺省參數會是怎樣的情況?看下面的程序:

    def fun2(a, b, c=0, d=0):
        print("a -- " + str(a))
        print("b -- " + str(b))
        print("c -- " + str(c))
        print("d -- " + str(d))
        return a + b + c + d

    print(fun2(2, 3, 4))

程序執行結果如下:

    a -- 2
    b -- 3
    c -- 4
    d -- 0
    9

說明,前面的位置參數是必須要傳入的,c 的值是 4 ,而 d 的值是默認值 0 ,這說明,傳入的部分缺省參數會按順序賦值。如果偏要將 4 賦給 d ,而 c 用默認參數呢,則用下面方式調用函數即可:
print(fun2(2, 3, d=4))
程序結果:

    a -- 2
    b -- 3
    c -- 0
    d -- 4
    9

不止是缺省參數,位置參數也可以在調用函數時,也可以指定具體的值賦給哪個參數。

值得注意的是:定義函數時缺省參數要放在位置參數後面,如果向下面這樣定義:

    def fun2(a, b=0, c):
        return a + b + c

則會報錯:SyntaxError: non-default argument follows default argument

熟悉 java、C# 或者 C++ 等語言的應該知道“重載方法”的概念。參數列表不相同,包括參數的類型不相同和參數的個數不相同。在python中,用缺省參數,正好可以實現重載類似的效果。

可變參數(不定長參數)

在Python函數中,還可以定義可變參數,也叫不定長參數。顧名思義,可變參數就是傳入的參數個數是可變的,寫法爲,在參數前面加上一個 * ,類似於 java 中的不定長參數。不同的是,java中不定長參數,以數組形式存儲,在python中,可變參數則是一個元組。看下面的程序:

    def fun3(a, *b):
        print(type(a))
        print(a)
        print(type(b))
        print(b)

    fun3(1, 2, 3, 4, 5)

輸出結果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, 3, 4, 5)

程序中,函數 fun3 的參數 a 是一個 int 型,後面 *b 即爲可變參數,在調用時,可以根據需要傳入不同個數的參數,除去 a 之後,剩餘所有的參數,都添加到一個元組中。

看下面的調用:
fun3(1, 2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
輸出結果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)

結果顯示很明確了,即便我傳入列表,元組,字典類型的參數,也會被當做元組的元素,添加進去。
約定俗成,函數中的可變參數一般用 *args 來表示。

關鍵字參數

最後說說 python 的關鍵字參數。python 關鍵字參數是在參數前面加上 ** ,和可變參數有點類似,區別在於,關鍵字參數是以字典形式存儲。調用的時候也有區別,看下面的程序:

    def fun4(a, *b, **c):
        print(type(c))
        print(a)
        print(b)
        print(c)

    fun4(1, 2, 3, 4, 5, x=6, y=7)

程序結果:

    <class 'dict'>
    1
    (2, 3, 4, 5)
    {'x': 6, 'y': 7}

結果顯示,參數 C 的類型是 dict 字典。在調用時,需要按照 key = value 的形式傳入關鍵字參數。約定俗成,關鍵字參數一般用 **kwargs 來表示。按照上面的寫法,我們調用函數時可以隨意傳入關鍵字參數,有時候,我們需要限定關鍵字參數的 'key' ,這樣我們可以使用命名關鍵字參數。比如,上面的程序,我在調用時關鍵字參數,傳入了 'x' 和 'y',事實上,我想的話,還可以傳入更多的參數 ,用命名關鍵字參數,則可以限定,只傳入 'x' 和 'y' ,程序如下:

    def fun5(a, *, x, y):
        print(a)
        print(x)
        print(y)


    fun5(1, x=2, y=3)

輸出結果:

    1
    2
    3

即用一個 *,,後面跟上指定的參數。這樣,你如果多傳,或者少穿關鍵字參數,都是不可以的。

可變參數和關鍵字參數拆包

再回頭看前面的例子:

    def fun3(a, *b):
        print(type(a))
        print(a)
        print(type(b))
        print(b)

    fun3(1, 2, 3, 4, 5)

執行 fun3(1, 2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)
輸出結果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, (3, 4, 5), [6, 7], {'x': 8, 'y': 9}, 10, 11)

這裏,傳入參數的 (3,4,5) 和 [6,7] 和 {'x': 8, 'y': 9} 都被當作元組裏面的元素了。下面在調用時,參數前面添加一個 * ,如下:
fun3(1, 2, *(3, 4, 5), *[6, 7], *{'x': 8, 'y': 9}, 10, 11)

結果如下:

    <class 'int'>
    1
    <class 'tuple'>
    (2, 3, 4, 5, 6, 7, 'x', 'y', 12, 13)

看結果,在列表或者元組參數前面添加 * 之後,卻反而被拆開成單個元素,作爲元組的元素。而字典,只是把它的 'key' 拆成單個元素。這就是可變參數的拆包。一般,可變參數的拆包我們只針對元組和列表,不針對字典。
同樣,對於含有關鍵字參數的函數,也可對傳入的參數進行拆包,看下面這個函數:

    def fun6(**kwargs):
        print(kwargs)

下面我調用函數 fun6({'x': 1, 'y': 2}) ,這時候,程序會報錯

因爲,關鍵字參數,在調用的時候傳參,需要按照 key = value 的形式傳入。而我現在傳入一個字典,會被當做一個整體,作爲一個位置參數傳入。如果以下面這種方式
fun6(**{'x': 1, 'y': 2})
調用,則可行,結果如下:

    {'x': 1, 'y': 2}

即通過 ** 將字典拆成了 'x'=1 , 'y'=2 的形式。這就是關鍵字參數的拆包。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章