07-02 函數(shù)的參數(shù)

目錄

  • 一 形參與實(shí)參介紹
  • 二 形參與實(shí)參的具體使用
    • 2.1 位置參數(shù)
    • 2.2 關(guān)鍵字參數(shù)
    • 2.3 默認(rèn)參數(shù)
    • 2.4 可變長度的參數(shù) (*用法)
      • 2.4.1 可變長度的位置參數(shù)
      • 2.4.2 可變長度的關(guān)鍵字參數(shù)
    • 2.5 命名關(guān)鍵字參數(shù)
    • 2.6 組合使用
  • 三 視頻鏈接

一 形參與實(shí)參介紹

函數(shù)的參數(shù)分為形式參數(shù)和實(shí)際參數(shù),簡稱形參和實(shí)參:

形參即在定義函數(shù)時(shí),括號內(nèi)聲明的參數(shù)。形參本質(zhì)就是一個變量名,用來接收外部傳來的值。

實(shí)參即在調(diào)用函數(shù)時(shí),括號內(nèi)傳入的值,值可以是常量、變量、表達(dá)式或三者的組合:

#1:實(shí)參是常量
res=my_min(1,2)

#2:實(shí)參是變量
a=1
b=2
res=my_min(a,b)

#3:實(shí)參是表達(dá)式
res=my_min(10*2,10*my_min(3,4))

#4:實(shí)參可以是常量、變量、表達(dá)式的任意組合
a=2
my_min(1,a,10*my_min(3,4))

在調(diào)用有參函數(shù)時(shí),實(shí)參(值)會賦值給形參(變量名)。在Python中,變量名與值只是單純的綁定關(guān)系,而對于函數(shù)來說,這種綁定關(guān)系只在函數(shù)調(diào)用時(shí)生效,在調(diào)用結(jié)束后解除。

二 形參與實(shí)參的具體使用

2.1 位置參數(shù)

位置即順序,位置參數(shù)指的是按順序定義的參數(shù),需要從兩個角度去看:

  1. 在定義函數(shù)時(shí),按照從左到右的順序依次定義形參,稱為位置形參,凡是按照這種形式定義的形參都必須被傳值

    >>> def register(name,age,sex): #定義位置形參:name,age,sex,三者都必須被傳值
    ...     print('Name:%s Age:%s Sex:%s' %(name,age,sex))
    ... 
    >>> register() #TypeError:缺少3個位置參數(shù)
    
  2. 在調(diào)用函數(shù)時(shí),按照從左到右的順序依次定義實(shí)參,稱為位置實(shí)參,凡是按照這種形式定義的實(shí)參會按照從左到右的順序與形參一一對應(yīng)

    >>> register('lili',18,'male') #對應(yīng)關(guān)系為:name=’lili’,age=18,sex=’male’
    Name:lili Age:18 Sex:male
    

2.2 關(guān)鍵字參數(shù)

在調(diào)用函數(shù)時(shí),實(shí)參可以是key=value的形式,稱為關(guān)鍵字參數(shù),凡是按照這種形式定義的實(shí)參,可以完全不按照從左到右的順序定義,但仍能為指定的形參賦值

>>> register(sex='male',name='lili',age=18)
Name:lili Age:18 Sex:male

需要注意在調(diào)用函數(shù)時(shí),實(shí)參也可以是按位置或按關(guān)鍵字的混合使用,但必須保證關(guān)鍵字參數(shù)在位置參數(shù)后面,且不可以對一個形參重復(fù)賦值

>>> register('lili',sex='male',age=18) #正確使用
>>> register(name='lili',18,sex='male') #SyntaxError:關(guān)鍵字參數(shù)name=‘lili’在位置參數(shù)18之前
>>> register('lili',sex='male',age=18,name='jack') #TypeError:形參name被重復(fù)賦值

2.3 默認(rèn)參數(shù)

在定義函數(shù)時(shí),就已經(jīng)為形參賦值,這類形參稱之為默認(rèn)參數(shù),當(dāng)函數(shù)有多個參數(shù)時(shí),需要將值經(jīng)常改變的參數(shù)定義成位置參數(shù),而將值改變較少的參數(shù)定義成默認(rèn)參數(shù)。例如編寫一個注冊學(xué)生信息的函數(shù),如果大多數(shù)學(xué)生的性別都為男,那完全可以將形參sex定義成默認(rèn)參數(shù)

>>> def register(name,age,sex='male'): #默認(rèn)sex的值為male
...     print('Name:%s Age:%s Sex:%s' %(name,age,sex))
...

定義時(shí)就已經(jīng)為參數(shù)sex賦值,意味著調(diào)用時(shí)可以不對sex賦值,這降低了函數(shù)調(diào)用的復(fù)雜度

>>> register('tom',17) #大多數(shù)情況,無需為sex傳值,默認(rèn)為male
Name:tom Age:17 Sex:male
>>> register('Lili',18,'female') #少數(shù)情況,可以為sex傳值female
Name:Lili Age:18 Sex:female

需要注意:

  1. 默認(rèn)參數(shù)必須在位置參數(shù)之后
  2. 默認(rèn)參數(shù)的值僅在函數(shù)定義階段被賦值一次
>>> x=1
>>> def foo(arg=x):
...     print(arg)
... 
>>> x=5 #定義階段arg已被賦值為1,此處的修改與默認(rèn)參數(shù)arg無任何關(guān)系
>>> foo()
1
  1. 默認(rèn)參數(shù)的值通常應(yīng)設(shè)為不可變類型

    >>> def foo(n,arg=[]):
    ...     arg.append(n)
    ...     return arg
    ... 
    >>> foo(1)
    [1]
    >>> foo(2)
    [1, 2]
    >>> foo(3)
    [1, 2, 3]
    

    每次調(diào)用是在上一次的基礎(chǔ)上向同一列表增加值,修改如下

    >>> def foo(n,arg=None):
    ...     if arg is None:
    ...         arg=[]
    ...     arg.append(n)
    ...     return arg
    ... 
    >>> foo(1)
    [1]
    >>> foo(2)
    [2]
    >>> foo(3)
    [3]
    

2.4 可變長度的參數(shù)(*的用法)

參數(shù)的長度可變指的是在調(diào)用函數(shù)時(shí),實(shí)參的個數(shù)可以不固定,而在調(diào)用函數(shù)時(shí),實(shí)參的定義無非是按位置或者按關(guān)鍵字兩種形式,這就要求形參提供兩種解決方案來分別處理兩種形式的可變長度的參數(shù)

2.4.1 可變長度的位置參數(shù)

如果在最后一個形參名前加號,那么在調(diào)用函數(shù)時(shí),溢出的位置實(shí)參,都會被接收,以元組的形式保存下來賦值給該形參

>>> def foo(x,y,z=1,*args): #在最后一個形參名args前加*號
...     print(x)
...     print(y)
...     print(z)
...     print(args)
... 
>>> foo(1,2,3,4,5,6,7)  #實(shí)參1、2、3按位置為形參x、y、z賦值,多余的位置實(shí)參4、5、6、7都被*接收,以元組的形式保存下來,賦值給args,即args=(4, 5, 6,7)

1
2
3
(4, 5, 6, 7)

如果我們事先生成了一個列表,仍然是可以傳值給*args的

>>> def foo(x,y,*args):
...     print(x)
...     print(y)
...     print(args)
... 
>>> L=[3,4,5]
>>> foo(1,2,*L) # *L就相當(dāng)于位置參數(shù)3,4,5, foo(1,2,*L)就等同于foo(1,2,3,4,5)
1
2
(3, 4, 5)

注意:如果在傳入L時(shí)沒有加*,那L就只是一個普通的位置參數(shù)了

>>> foo(1,2,L) #僅多出一個位置實(shí)參L
1
2
([1, 2, 3],)

如果形參為常規(guī)的參數(shù)(位置或默認(rèn)),實(shí)參仍可以是*的形式

>>> def foo(x,y,z=3):
...     print(x)
...     print(y)
...     print(z)
... 
>>> foo(*[1,2]) #等同于foo(1,2)
1
2
3

如果我們想要求多個值的和,*args就派上用場了

>>> def add(*args):
...     res=0
...     for i in args:
...         res+=i
...     return res
... 
>>> add(1,2,3,4,5)
15

2.4.2 可變長度的關(guān)鍵字參數(shù)

如果在最后一個形參名前加號,那么在調(diào)用函數(shù)時(shí),溢出的關(guān)鍵字參數(shù),都會被接收,以字典的形式保存下來賦值給該形參

>>> def foo(x,**kwargs): #在最后一個參數(shù)kwargs前加**
...     print(x)        
...     print(kwargs)   
... 
>>> foo(y=2,x=1,z=3) #溢出的關(guān)鍵字實(shí)參y=2,z=3都被**接收,以字典的形式保存下來,賦值給kwargs
1
{'z': 3, 'y': 2}

如果我們事先生成了一個字典,仍然是可以傳值給**kwargs的

>>> def foo(x,y,**kwargs):
...     print(x)
...     print(y)
...     print(kwargs)
... 
>>> dic={'a':1,'b':2} 
>>> foo(1,2,**dic) #**dic就相當(dāng)于關(guān)鍵字參數(shù)a=1,b=2,foo(1,2,**dic)等同foo(1,2,a=1,b=2)
1
2
{'a': 1, 'b': 2}

注意:如果在傳入dic時(shí)沒有加**,那dic就只是一個普通的位置參數(shù)了

>>> foo(1,2,dic) #TypeError:函數(shù)foo只需要2個位置參數(shù),但是傳了3個

如果形參為常規(guī)參數(shù)(位置或默認(rèn)),實(shí)參仍可以是**的形式

>>> def foo(x,y,z=3):
...     print(x)
...     print(y)
...     print(z)
... 
>>> foo(**{'x':1,'y':2}) #等同于foo(y=2,x=1)
1
2
3

如果我們要編寫一個用戶認(rèn)證的函數(shù),起初可能只基于用戶名密碼的驗(yàn)證就可以了,可以使用**kwargs為日后的擴(kuò)展供良好的環(huán)境,同時(shí)保持了函數(shù)的簡潔性。

>>> def auth(user,password,**kwargs): 
...     pass 
...

2.5 命名關(guān)鍵字參數(shù)

在定義了**kwargs參數(shù)后,函數(shù)調(diào)用者就可以傳入任意的關(guān)鍵字參數(shù)key=value,如果函數(shù)體代碼的執(zhí)行需要依賴某個key,必須在函數(shù)內(nèi)進(jìn)行判斷

>>> def register(name,age,**kwargs):
...     if 'sex' in kwargs:
...         #有sex參數(shù)
...         pass
...     if 'height' in kwargs:
...         #有height參數(shù)
...         pass
... 

想要限定函數(shù)的調(diào)用者必須以key=value的形式傳值,Python3提供了專門的語法:需要在定義形參時(shí),用作為一個分隔符號,號之后的形參稱為命名關(guān)鍵字參數(shù)。對于這類參數(shù),在函數(shù)調(diào)用時(shí),必須按照key=value的形式為其傳值,且必須被傳值

>>> def register(name,age,*,sex,height): #sex,height為命名關(guān)鍵字參數(shù)
...     pass
... 
>>> register('lili',18,sex='male',height='1.8m') #正確使用
>>> register('lili',18,'male','1.8m') # TypeError:未使用關(guān)鍵字的形式為sex和height傳值
>>> register('lili',18,height='1.8m') # TypeError沒有為命名關(guān)鍵字參數(shù)height傳值。

命名關(guān)鍵字參數(shù)也可以有默認(rèn)值,從而簡化調(diào)用

>>> def register(name,age,*,sex='male',height):
...     print('Name:%s,Age:%s,Sex:%s,Height:%s' %(name,age,sex,height))
... 
>>> register('lili',18,height='1.8m')
Name:lili,Age:18,Sex:male,Height:1.8m

需要強(qiáng)調(diào)的是:sex不是默認(rèn)參數(shù),height也不是位置參數(shù),因?yàn)槎呔?em>后,所以都是命名關(guān)鍵字參數(shù),形參sex=’male’屬于命名關(guān)鍵字參數(shù)的默認(rèn)值,因而即便是放到形參height之前也不會有問題。另外,如果形參中已經(jīng)有一個args了,命名關(guān)鍵字參數(shù)就不再需要一個單獨(dú)的*作為分隔符號了

>>> def register(name,age,*args,sex='male',height):
...   print('Name:%s,Age:%s,Args:%s,Sex:%s,Height:%s' %(name,age,args,sex,height))
... 
>>> register('lili',18,1,2,3,height='1.8m') #sex與height仍為命名關(guān)鍵字參數(shù)
Name:lili,Age:18,Args:(1, 2, 3),Sex:male,Height:1.8m

2.6 組合使用

綜上所述所有參數(shù)可任意組合使用,但定義順序必須是:位置參數(shù)、默認(rèn)參數(shù)、args、命名關(guān)鍵字參數(shù)、*kwargs

可變參數(shù)args與關(guān)鍵字參數(shù)kwargs通常是組合在一起使用的,如果一個函數(shù)的形參為args與**kwargs,那么代表該函數(shù)可以接收任何形式、任意長度的參數(shù)

>>> def wrapper(*args,**kwargs):
...     pass
...

在該函數(shù)內(nèi)部還可以把接收到的參數(shù)傳給另外一個函數(shù)(這在4.6小節(jié)裝飾器的實(shí)現(xiàn)中大有用處)

>>> def func(x,y,z):
...     print(x,y,z)
... 
>>> def wrapper(*args,**kwargs):
...     func(*args,**kwargs)
...
>>> wrapper(1,z=3,y=2)
1 2 3

按照上述寫法,在為函數(shù)wrapper傳參時(shí),其實(shí)遵循的是函數(shù)func的參數(shù)規(guī)則,調(diào)用函數(shù)wrapper的過程分析如下:

  1. 位置實(shí)參1被接收,以元組的形式保存下來,賦值給args,即args=(1,),關(guān)鍵字實(shí)參z=3,y=2被*接收,以字典的形式保存下來,賦值給kwargs,即kwargs={'y': 2, 'z': 3}
  2. 執(zhí)行func(args,kwargs),即func((1,),* {'y': 2, 'z': 3}),等同于func(1,z=3,y=2)
提示: *args、**kwargs中的args和kwargs被替換成其他名字并無語法錯誤,但使用args、kwargs是約定俗成的。
image.png

加qq群830644110獲取更多高級文章&項(xiàng)目源代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評論 2 380