python之函式的引數詳解
阿新 • • 發佈:2020-09-11
引數傳遞:
-
不可變資料型別:數字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
-
可變資料型別:列表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]
引數型別
-
位置引數:即按照位置傳入引數,引數的個數、位置、型別必須匹配。如:
def power(x, n): s = 1 while n > 0: n = n - 1 s = s * x return s print(power(2,3)) out: 8
-
預設值引數:是指該引數有預設值,預設值必須是不可變資料型別。如:
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
-
可變引數:可變引數允許傳入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
-
命名關鍵字引數:必須傳入引數名,不指定名字傳參會報錯。另外命名關鍵字引數也可指定預設值,有預設值的可以不傳參。如:
def person(*, name, age): print(name, age) person(name='Mike', age=20) #person('Mike',20) # 不指定名字傳參會報錯 out: Mike 20
-
關鍵字引數:允許傳入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}
------------------------------