給妹子講python--21函數參數的匹配與解包

陪伴學習,一路成長。請一起關注,一起點贊吧!

【要點搶先看】

1.基於位置和關鍵字的參數匹配n2.使用默認參數形式n3.函數定義使用*和**進行任意數目參數收集n4.函數調用時使用*和**進行參數解包n

正如我們之前所講的,參數在python中總是通過賦值進行傳遞的。在默認情況下,參數是通過其位置進行匹配的,從左到右,而且必須精確的傳遞和函數頭部參數名一樣多的參數。

這種默認的傳遞方式很簡單

def f(a,b,c):n print(a,b,c)nnf(1,2,3)nn1 2 3n

python中可以使用基於關鍵字的參數匹配形式。在調用函數的時候,能夠更詳盡的定義內容傳遞的位置。關鍵字參數允許通過變數名進行匹配,而不是通過位置。

def f(a,b,c):n print(a,b,c)nnf(c=3,a=1,b=2)nn1 2 3n

我們可以看出,當關鍵字參數使用時參數從左至右的關係已不再重要了,因為參數是通過變數名進行傳遞的,而不是通過其位置。這種調用顯得更文檔化一些(例如使用一些名稱更直觀的參數名)。

甚至在一個調用中混合使用基於位置的參數和基於關鍵字的參數也可以。在這種情況下,所有基於位置的參數首先按照從左到右的順序匹配頭部的參數,之後再進行基於變數名進行關鍵字的匹配。

def f(a,b,c):n print(a,b,c)nnf(1,c=3,b=2)nn1 2 3n

再來說說python中的默認參數形式。默認參數允許創建函數可選的參數,如果沒有傳入值的話,在函數運行前,參數就被賦予了默認值,還是看一個例子:

def f(a,b=2,c=3):n print(a,b,c)nnf(1)n1 2 3nnf(a=1)n1 2 3n

看到這個例子中,我們必須為a提供值,無論是通過位置參數還是關鍵字參數來實現,然而,為b和c提供值是可選的。如果我們不給b和c傳遞值,它們會分別賦值為2和3。

那麼按位置順序,當給函數傳遞兩個值的時候,只有c得到默認值,並且當有三個值傳遞時,不會使用默認值。

def f(a,b=2,c=3):n print(a,b,c)nnf(1,4)nn1 4 3nndef f(a,b=2,c=3):n print(a,b,c)nnf(1,4,8)nn1 4 8n

最後一種情況,是關鍵字和默認參數一起使用的情況。關鍵字參數允許我們跳過有默認值的參數,但是要記住的是,首先要完成通過位置進行匹配的參數。

def f(a,b=2,c=3):n print(a,b,c)nnf(1,c=6)nn1 2 6n

很明顯,a通過位置得到了1,c通過關鍵字得到了6,而跳過了b,b通過默認參數得到了2.

【妹子說】我有時看到函數定義的參數中有*和**符號,表示什麼意思?

這也是python中非常有特色的:當*和**符號出現在函數定義的參數中時,表示任意數目參數收集。

先說說*,他是用元組的形式收集不匹配的位置參數。當這個函數調用時,python將所有位置相關的參數收集到一個新的元組中,並將這個元組賦值給變數args。

def f(a,*args):n print(args)nnf(1,2,3,4)nn(2, 3, 4)n

再說說**的特性,他只對關鍵字參數有效。在這種情況下,**允許將關鍵字參數轉化為字典,你能夠在之後使用鍵調用來進行步進或字典迭代

def f(**kargs):n print(kargs)nnf(a=1,b=2)nn{b: 2, a: 1}n

最後我們來概況一下最一般的形式。即在函數頭部能混合一般參數、*參數以及**去實現更加靈活的調用方式。

def f(a, *pargs, **kargs):n print(a,pargs,kargs)nnf(1,2,3,x=4,y=5)nn1 (2, 3) {x: 4, y: 5}n

這個例子中,1按位置傳給a,2和3收集到pargs位置的元組中,x和y放入kargs關鍵字詞典中

上面是在函數定義的時候寫的*和**形式,那反過來,如果*和**語法出現在函數調用中又會如何呢?他會解包參數的集合。

例如,我們在調用函數時能夠使用*語法,在這種情況下,它與函數定義的意思相反,他會解包參數的集合,而不是創建參數的集合。例如我們可以通過一個元組給一個函數傳遞四個參數,並且讓python將它們解包成不同的參數。

def func(a,b,c,d):n print(a,b,c,d)nnargs = (1,2,3,4)nfunc(*args)nn1 2 3 4n

相似的,在函數調用時,**會以鍵/值對的形式解包一個字典,使其成為獨立的關鍵字參數。

def func(a,b,c,d):n print(a,b,c,d)nnkargs = {a:1, b:2, c:3, d:4}nfunc(**kargs)nn1 2 3 4n

當然這種形式也是可以混合的,從左到右要以位置參數、元組解包、關鍵字參數、字典解包的順序來進行

def func(a,b,c,d,e,f):n print(a,b,c,d,e,f)nnargs = (2, 3)nkargs = {d: 4, e: 5}nnfunc(1, *args, f=6, **kargs)nn1 2 3 4 5 6n

說了這些基本的知識,我們來看看一個實際應用的例子

這種支持任意參數形式的方法的一個應用點,就是實現對其他函數進行靈活調用。因為參數列表可以通過元組、字典形式傳入,所以他支持運行時構建參數列表,這對於測試和計時其他函數非常方便。在下面的代碼中,我們通過傳遞任何發送進來的參數來支持具有任意參數的任意函數:

def tracer(func, *args, **kargs):n print(calling:, func.__name__)n return func(*args, **kargs)nndef func(a,b,c,d):n return a+b+c+dnnprint(tracer(func,1,2,c=3,d=4))nncalling: funcn10n

很明顯,這裡在定義tracer函數時應用了收集任意參數的方法,在其中調用func函數時又利用了解包參數的方法。

最後綜合所學,我們舉一個例子,來仿寫一個函數模擬print的功能,他可以接收任意的位置參數,同時接收規定範圍內的關鍵字參數,對多餘的關鍵字參數會報錯。

import sysndef print30(*args, **kargs):n sep = kargs.pop(sep, )n end = kargs.pop(end, n)n file = kargs.pop(file, sys.stdout)n if kargs:n raise TypeError(extra keywords:{}.format(kargs))n output = n first = Truen for arg in args:n output += ( if first else sep) + str(arg)n first = Falsen file.write(output + end)nnprint30(hello,world,healthy,sep=&)nnhello&world&healthyn

在這段程序中,有幾個關鍵點值得我們注意

對kargs字典進行pop操作,彈出了指定的三個關鍵字sep、end、file後,如果字典里還有值,則證明是多餘的關鍵字,程序需要報錯。第二在pop的時候,如果這三個參數如果在調用函數的時候指定了值,就用指定的值,如果沒有指定值則用程序中指定的默認值。

從下面的例子就可以看出,使用多餘的關鍵字,程序會報錯。

print30(hello,world,healthy,sep=&,ppp=33,hhh=44)nnTraceback (most recent call last):n File "E:/12homework/12homework.py", line 15, in <module>n print30(hello,world,healthy,sep=&,ppp=33,hhh=44)n File "E:/12homework/12homework.py", line 7, in print30nraise TypeError(extra keywords:{}.format(kargs))nTypeError: extra keywords:{ppp: 33, hhh: 44}n

@金旭亮 請金老師也多多指導一下文章的邏輯性,多指教哈~


推薦閱讀:

基於阿里雲Serverless架構下函數計算的最新應用場景詳解
getchar函數運用問題?
數學和編程中「函數」的概念相同在哪裡,不同在哪裡?
微積分之函數,函數極限與連續
一個關於偏導數公式的問題:?u和?v為什麼不能約去?

TAG:Python | 函数 | 参数 |