python函式引數定義及解析(包含帶星號引數)
前言:python中函式引數的傳遞是通過賦值來傳遞的。函式的引數有兩個方面值得注意: 1.函式引數是如何定義的 2.在呼叫函式的過程中引數是如何被解析的
python函式引數的定義方式
func(arg1, arg2, …)
這是最常見的定義方式,一個函式可以定義任意個引數,每個引數間用逗號分割,用這種方式定義的函式在呼叫的的時候也必須在函式名後的小括號裡提供個數相等的值,也就是說在這種呼叫方式中,形參和實參的個數必須一致,而且必須一一對應,也就是說第一個形參對應這第一個實參。例 如:
def func(x, y):
print x,y
呼叫該函式,func(1,2)則x取1,y取2,形參與實參相對應,func(y=2, x=1)也會達到相同的效果;但如果func(1)或者func(1,2,3)則會報錯。
func(arg1, arg2=value2, …)
這種函式定義方式相對於第一種,提供了預設引數,也就是在呼叫該函式時,可以不用給預設引數傳參。例如:
def func(x, y=3):
print x,y
呼叫該函式,func(1,2)同樣還是x取1,y取2,但是如果func(1),則不會報錯了,這個時候x還是1,y則為預設的3。同第一種一樣,也可以更換引數位置,比如func(y=8, x=3)用這種形式也是可以的。
func(*args)
上面兩種方式是有多少個形參,就傳進去多少個實參,但有時候會不確定有多少個引數,則此時第三種方式就比較有用,它以一個*加上形參名的方式來表示這個函式的實參個數不定,可能為0個也可能為多個。注意一點是,不管有多少個,在函式內部都被存放在以形參名為識別符號的tuple中。例如:
def func1(*args):
if len(args) == 0:
print('args: None')
else:
print('args:', args)
func1() >> args: None
func1(1, 2, 3) >> args:(1, 2, 3)
func1(x=1,y=2,z=3) >> TypeError: func1() got an unexpected keyword argument 'x'
func(**args)
最後一種方式是形參前面加兩個星號,引數在函式內部將被存放在以形參名為識別符號的字典中,這時呼叫函式的方法則需要採用arg1=value1,arg2=value2這樣的形式。例如:
def func1(**args):
if len(args) == 0:
print('args: None')
else:
print('args:', args)
func1() >> args: None
func1(x=1, y=2, z=3) >> args: {'x': 1, 'y': 2, 'z': 3}
func1(1, 2, 3) >> TypeError: func1() takes 0 positional arguments but 3 were given
python函式引數的解析方式
python函式引數的解析方式按照之前定義的四種方法優先順序依次降低,先1,後2,再3,最後4;也就是先把方式1中的arg解析,然後解析方式2中的arg=value,再解析方式3,即是把多出來的arg這種形式的實參組成個tuple傳進去,最後把剩下的key=value這種形式的實參組成一個dictionary傳給帶倆個星號的形參,也就方式4。例如:
def func_test(w, x=1, *y, **z):
print(w, x, y, z)
func_test(1) >> 1 1 () {}
func_test(1,2) >> 1 2 () {}
func_test(1,2,3) >> 1 2 (3,) {}
func_test(1,2,3,4) >> 1 2 (3, 4) {}
func_test(w=1,x=2) >> 1 2 () {}
func_test(w=1,y=2) >> 1 1 () {'y': 2}
func_test(1,2,3,y=4) >> 1 2 (3,) {'y': 4}
func_test(1,2,3,x=4) >> TypeError: func_test() got multiple values for argument 'x'
def foo(*args, **kwarg):
for item in args:
print(item)
for k,v in kwarg.items():
print(k,v)
print(30*'=')
if __name__ == '__main__':
v1 = (1, 2, 3)
v2 = [4, 5, 6]
d = {'a':11, 'b':12}
foo(v1, d)
foo(*v1, **d)
foo(v2, d)
foo(*v2, **d)
結果如下:
(1, 2, 3)
{'a': 11, 'b': 12}
==============================
1
2
3
a 11
b 12
==============================
[4, 5, 6]
{'a': 11, 'b': 12}
==============================
4
5
6
a 11
b 12
==============================
上例中說明如果v1、v2、d沒有加星號那麼就當成了一個引數傳遞給了函式,如果加了星號那麼就會解包後傳遞給函式。
注意
- 可變位置引數*args是一個元組,是不可修改的,例如:
def func(*args):
args[0] = 4
func(1, 2, 3) >> TypeError: 'tuple' object does not support item assignment
- 對於字典型別的如果只使用一個型號*那麼傳入的只是字典的鍵,例如:
def func(*args, **kwarg):
print args, kwarg
d = {'a':1, 'b':2, 'c':3}
func(*d) >> ('a', 'b', 'c') {}
func(**d) >> () {'a': 1, 'b': 2, 'c': 3}
- 可以把字典或元組型別的引數通過解析傳入1型別定義的函式裡面,例如:
def func(a, b):
print("a: %d, b: %d" % (a, b))
c = a-b
return c
d = {"b": 5, "a": 3}
e = (3, 5)
f = (5, 3)
def main():
i = func(**d)
print("result: %d" %i)
j = func(*e)
print("result: %d" %j)
k = func(*f)
print("result: %d" %k)
m = func(b=2, a=1)
print(m)
if __name__ == '__main__':
main()
執行結果:
a: 3, b: 5
result: -2
a: 3, b: 5
result: -2
a: 5, b: 3
result: 2
a: 1, b: 2
result: -1