1. 程式人生 > 實用技巧 >python之函式的引數詳解

python之函式的引數詳解

引數傳遞:

  1. 不可變資料型別:數字number(含int、float、bool、complex)、字串string、元組tuple。

    當不可變資料型別被當作函式的引數,傳遞的是值,函式體內改變值時實際是生成新的物件,不會影響函式體外原來的值。例如:

    x=10
    def print_add_ten(x):
        x+=10
        print(x)
    print_add_ten(x)
    print(x)
    
    out:
    20
    10
    
  2. 可變資料型別:列表list、字典dict、集合set。

    當可變資料型別被當作函式的引數,傳遞的是引用,函式體內改變值時會影響函式體外的值。例如:

    x=[1,2,3,4,5]
    def print_change_list(x):
        x[0]=10
        print(x)
    print_change_list(x)
    print(x)
    
    out:
    [10, 2, 3, 4, 5]
    [10, 2, 3, 4, 5]
    

    上述這個函式看起來沒有問題,但在特殊場合會導致不可預料的bug。推薦的方式是對可變資料型別引數做copy(注意若存在巢狀結構需要用deepcopy),然後做處理,並將處理結果返回給呼叫者。例如:

    x=[1,2,3,4,5]
    def print_change_list(x):
        x=x.copy()
        x[0]=10
        return x
    print(print_change_list(x))
    print(x)
    
    out:
    [10, 2, 3, 4, 5]
    [1, 2, 3, 4, 5]
    

引數型別

  1. 位置引數:即按照位置傳入引數,引數的個數、位置、型別必須匹配。如:

    def power(x, n):
        s = 1
        while n > 0:
            n = n - 1
            s = s * x
        return s
    
    print(power(2,3))
    
    out:
    8
    
  2. 預設值引數:是指該引數有預設值,預設值必須是不可變資料型別。如:

    def power(x, n=2):
        s = 1
        while n > 0:
            n = n - 1
            s = s * x
        return s
    print(power(2))
    print(power(2,3))
    
    out:
    4
    8
    
  3. 可變引數:可變引數允許傳入0個或任意個引數,這些引數在函式呼叫時被封裝到一個元組,並將這個元組賦值給了args。如:

    def calc(*args):  # args是約定俗成的名字,可以自定義,但建議用args
        sum = 0
        for n in args:
            sum = sum + n * n
        return sum
    
    print(calc(1,2,3))
    
    out:
    14
    
  4. 命名關鍵字引數:必須傳入引數名,不指定名字傳參會報錯。另外命名關鍵字引數也可指定預設值,有預設值的可以不傳參。如:

    def person(*, name, age):
        print(name, age)
    
    person(name='Mike', age=20)
    #person('Mike',20)  # 不指定名字傳參會報錯
    
    out:
    Mike 20
    
  5. 關鍵字引數:允許傳入0個或任意個含引數名的引數,這些關鍵字引數在函式呼叫時被封裝到一個字典中,並將這個字典賦值給了kwargs。但關鍵字引數不能指定哪些關鍵字必須有。如:

    def person(**kwargs):  # kwargs是約定俗成的名字,可以自定義,但建議用kwargs
        print(kwargs)
    
    person(name='Mike',age=20)
    person(gender='men',height=180)
    
    out:
    {'name': 'Mike', 'age': 20}
    {'gender': 'men', 'height': 180}
    

    補充幾點:

    • 預設值引數是一種特殊的位置引數或者命名關鍵字引數,即該引數有預設值。如果不傳參,那麼該引數取值為預設值(必須是不可變資料型別);如果傳了參那麼取值為傳的參。
    • 關鍵字引數實際是將引數名和引數值封裝成字典傳給函式。但是關鍵字引數的key不固定會導致寫程式碼不方便。所以又有命名關鍵字引數,命名關鍵字引數是key固定而value不定的鍵值對,方便編寫程式碼。
    • 位置引數和命名關鍵字引數的區別:
      • 位置引數可按位置傳參,也可用名字傳參,位置引數必須定義在可變引數前面
      • 命名關鍵字引數必須指定名字傳參,命名關鍵字引數必須定義在可變引數後面(如果沒有可變引數時用*代替)。
    • *和**在函式定義時表示封裝,在函式呼叫時代表拆包。
def func(*args, **kwargs):
    print(args)
    print(kwargs)
    print('-'*30)


func([1, 2, 3], [22, 33])  # 不拆包時函式接收的是2個列表
func(*[1, 2, 3], *[22, 33])  # 可迭代物件均可拆包,拆包後函式接收到的是一個元組。
func({'name': '張三'}, {'age': 20})  # 這樣傳參的2個字典被args接收,kwargs接收的是空字典
func(**{'name': '張三'}, **{'age': 20})  # 這樣傳參的2個字典被kwargs接收,args接收的是空元組

out:
([1, 2, 3], [22, 33])
{}
------------------------------
(1, 2, 3, 22, 33)
{}
------------------------------
({'name': '張三'}, {'age': 20})
{}
------------------------------
()
{'name': '張三', 'age': 20}
------------------------------