1. 程式人生 > >python之函式引數

python之函式引數

前記
    定義函式時,把引數的名字和位置確定,函式的介面定義就完成。函式呼叫者只需要知道如何傳遞正確的引數,以及函式返回什麼值,函式內部的邏輯被封裝;
    python函式定義中,除了正常定義的必選引數外,還有預設引數、可變引數、關鍵字引數。
    預設引數一定要用不可變物件。
    可變引數和關鍵字引數:
        *args:可變引數,args接收一個tuple;
        **kw:關鍵字引數,kw接收一個dict;
        可變引數可直接傳入,如func(1,2,3),又可組裝list或tuple,再通過*args傳入,如func(*(1,2,3));
        關鍵字引數可直接傳入,如func(a=1,b=2),又可組裝dict,再通過**kw傳入,如func(**{'1':a,'2':b});
    命名關鍵字引數,可限制呼叫者傳入的引數名,同時可提供預設值。
    定義命名的關鍵字引數在沒有可變引數條件下,一定要使用分隔符*,否則定義的是位置引數。


一、位置引數
    示例:
    def power(x):
        return x*x

    print(power(5))
    power(x)函式中,x就是位置引數。呼叫power(x)時,必須傳入有且僅有一個引數x。

    示例:
    def power(x,n):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

    print(power(5,2))
    power(x,n)計算任意n次方,有兩個位置引數,呼叫函式時,傳入的兩個值按照位置順序依次賦給x和n。

二、預設引數
    示例:
    def power(x,n = 2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

    print(power(5))
    print(power(5,2))
    第二個引數n預設為2,預設引數可簡化函式的呼叫。
    設定預設引數時,注意:
    1、必選引數在前,預設引數在後。
    2、當函式有多個引數時,變化大的引數方前面,變化小的引數放後面。變化小的作為預設引數。
    3、當不按順序提供預設引數時,需要把引數名寫上。

    預設引數的坑:
    def add_end(L=[]):
    L.append('END')
    return L

    print(add_end())
    print(add_end())
    輸出:
    ['END']
    ['END', 'END']

    原因:python函式定義時,預設引數L的值就被計算出來了,即[],預設引數是一個變數,指向物件[],每次呼叫函式,如果改變L的內容,則下次呼叫時,預設引數的內容就變了,不再是定義的[].
    牢記:預設引數必須指向不變物件。    

    test:
    def add_end(L=[]):
        print("L init is",L)
        L.append('END')
        return L

    print(add_end())
    print(add_end())
    輸出:
    L init is []
    ['END']
    L init is ['END']
    ['END', 'END']

    修改上面示例,用None不變物件實現:
    def add_end(L=None):
    if L == None:
        L = []
    L.append('END')
    return L

    print(add_end())
    print(add_end())
    輸出:
    ['END']
    ['END']

    注:不變物件一旦建立,物件內部的資料不能修改。

三、可變引數
    即傳入的引數個數是可變的。
    示例:
    def calc(numbers):
    sum = 0
    for n in numbers:
        sum = sum + n
    return sum

    print(calc([1,2,3,4]))
    print(calc((1,2,3,4)))
    輸出:
    10
    10
    結論:把引數作為list或tuple傳入;
    利用可變引數,如下示例:
    def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n
    return sum

    print(calc(1,2,3,4))
    輸出:
    10
    結論:定義可變引數和定義一個list或tuple引數相比,僅僅在引數前面加一個*號。在函式內部,引數接收到的是一個tuple。

    如果有一個list或tuple,呼叫可變引數:
    nums=[1,2,3]
    print(calc(*nums))
    *nums表示把nums這個list的所有元素作為可變引數傳進去。

四、關鍵字引數
    可變引數允許傳入任意個引數,可變引數在函式呼叫時自動組裝為一個tuple。
    關鍵字引數允許傳入任意個含引數名的引數。這些關鍵字引數在函式內部自動組裝為一個dict。
    示例:
    def person(name,age,**kw):
        print("name=",name,"age=",age,"kw=",kw)

    person("Michael",24)
    person("Tom",30,city="beijing",job="Engineer")
    extra = {"city":"shanghai","job": "Engineer"}
    person("Jack",28,**extra)
    輸出:
    name= Michael age= 24 kw= {}
    name= Tom age= 30 kw= {'city': 'beijing', 'job': 'Engineer'}
    name= Jack age= 28 kw= {'city': 'shanghai', 'job': 'Engineer'}
    結論:**extra表示把extra這個dict的所有ke-value用關鍵字引數傳入函式的**kw引數,kw獲得一個dict,即kw獲得extra的一份拷貝,對kw的修改不影響extra。

五、命名關鍵字引數
    對於關鍵字引數,呼叫者可傳入任意不受限制的關鍵字引數。
    如果限制關鍵字引數的名字,可以用命名關鍵字引數。
    示例:
    def person(name,age,*,city,job):
    print(name,age,city,job)

    person("Jack",28,city="beijing",job="Engineer")
    輸出:
    Jack 28 beijing Engineer

    結論:和關鍵字**kw不同,命名關鍵字引數使用*隔開,*後面的引數視為命名關鍵字引數。

    示例:
    def person(name,age,*args,city,job):
    print(name,age,args,city,job)

    person("Jack",28,city="beijing",job="Engineer")
    #person("Jack",28,"beijing","Engineer")
    #上面語句報錯:SyntaxError: invalid character in identifier
    輸出:
    Jack 28 () beijing Engineer


六、引數組合
    定義函式,可將必選引數、預設引數、可變引數、關鍵字引數、命名關鍵字引數,5種組合使用;
    注意:引數順序必須是:必選引數、預設引數、可變引數、關鍵字引數、命名關鍵字引數。

    def f1(a, b, c=0, *args, **kw):
        print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

    def f2(a, b, c=0, *, d, **kw):
           print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

    f1(1, 2, 3, 'a', 'b', x=99)
    f2(1, 2, d=99, ext=None)

    args = (1, 2, 3, 4)
    kw = {'d': 99, 'x': '#'}
    f1(*args, **kw)

    args = (1, 2, 3)
    kw = {'d': 88, 'x': '#'}
    f2(*args, **kw)
    輸出:
    a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
    a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
    a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
    a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
    結論:
    1、python自動按照引數位置和引數名把對應引數傳入;
    2、任意函式,都可通過func(*args,**kw)形式呼叫;
    3、不要同時使用太多組合,會導致函數借口可理解性差。

注:如有錯誤,請指正。