python基礎(十二):函數的參數

一、形參和實參是什麼?

函數的參數分爲形式參數和實際參數,簡稱形參和實參:
形參即在定義函數時,括號內聲明的參數。形參本質就是一個變量名,用來接收外部傳來的值。

def func(x,y): #x和y爲形參
	print(x,y)

實參即在調用函數時,括號內傳入的值,值可以是常量、變量、表達式或三者的組合。

func(1,2) #1和2爲實參

形參和實參的關係:

在調用階段,實參(變量值)會賦值給形參(變量名)

二、形參與實參的具體使用

1、兩種形參的區別

(1)位置形參

在定義函數時,按照從左到右的順序依次定義形參,稱爲位置形參,凡是按照這種形式定義的形參都必須被傳值

def register(name,age,sex): #定義位置形參:name,age,sex,三者都必須被傳值
    print('Name:{} Age:{} Sex:{}'.format(name,age,sex))
(2)默認形參

默認形參調用時,可以不傳值,那麼就是默認值,傳值就覆蓋默認值。

>>> def register(name,age,sex='male'): #默認sex的值爲male
...     print('Name:{} Age:{} Sex:{}'.format(name,age,sex))
...

需要注意:

  • 默認參數必須在位置參數之後
  • 默認參數的值僅在函數定義階段被賦值一次
  • 默認參數的值通常應設爲不可變類型
def foo(n,arg=[]):    
     arg.append(n)    
     return arg    
foo(1)    
[1] 
foo(2)    
[1, 2] 
foo(3)    
[1, 2, 3]

每次調用是在上一次的基礎上向同一列表增加值,修改如下

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、兩種實參的區別

(1)位置實參

在調用函數時,按照從左到右的順序依次定義實參,稱爲位置實參,凡是按照這種形式定義的實參會按照從左到右的順序與形參一一對應

def register(name,age,sex): #定義位置形參:name,age,sex,三者都必須被傳值
    print('Name:{} Age:{} Sex:{}'.format(name,age,sex))
register('吳晉丞',18,'男') #定義位置實參:'吳晉丞',18,'男',按照順序和形參相對應
(2)關鍵字實參

在調用函數時,實參可以是key=value的形式,稱爲關鍵字參數,凡是按照這種形式定義的實參,可以完全不按照從左到右的順序定義,但仍能爲指定的形參賦值

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

需要注意在調用函數時,實參也可以是按位置或按關鍵字的混合使用,但必須保證關鍵字參數在位置參數後面,且不可以對一個形參重複賦值

>>> register('lili',sex='male',age=18) #正確使用

#錯誤示例:
>>> register(name='lili',18,sex='male') #SyntaxError:關鍵字參數name=‘lili’在位置參數18之前
>>> register('lili',sex='male',age=18,name='jack') #TypeError:形參name被重複賦值

3、可變長參數

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

(1)可變長位置參數在形參和實參中的應用
  • 形參中的應用

如果在最後一個形參名前加*號,那麼在調用函數時,溢出的位置實參,都會被接收,以元組的形式保存下來賦值給該形參

>>> def foo(x,y,z=1,*args): #在最後一個形參名args前加*號
...     print(x)
...     print(y)
...     print(z)
...     print(args)
... 
>>> foo(1,2,3,4,5,6,7)  #實參1、2、3按位置爲形參x、y、z賦值,多餘的位置實參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就相當於位置參數3,4,5。foo(1,2,*L)就等同於foo(1,2,3,4,5)
1
2
(3, 4, 5)
(2)可變長關鍵字參數在形參和實參中的應用
  • 形參中的應用

如果在最後一個形參名前加**號,那麼在調用函數時,溢出的關鍵字參數,都會被接收,以字典的形式保存下來賦值給該形參

>>> def foo(x,**kwargs): #在最後一個參數kwargs前加**
...     print(x)        
...     print(kwargs)   
... 
>>> foo(y=2,x=1,z=3) #溢出的關鍵字實參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就相當於關鍵字參數a=1,b=2。foo(1,2,**dic)等同foo(1,2,a=1,b=2)
1
2
{'a': 1, 'b': 2}

4、命名關鍵字參數(瞭解)

想要限定函數的調用者必須以key=value的形式傳值,Python3提供了專門的語法:需要在定義形參時,用*號作爲一個分隔符號,*號之後的形參稱爲命名關鍵字參數。對於這類參數,在函數調用時,必須按照key=value的形式爲其傳值,且必須被傳值。

>>> def register(name,age,*,sex,height): #sex,height爲命名關鍵字參數
...     pass
... 
>>> register('lili',18,sex='male',height='1.8m') #正確使用

#錯誤示例:
>>> register('lili',18,'male','1.8m') # TypeError:未使用關鍵字的形式爲sex和height傳值
>>> register('lili',18,height='1.8m') # TypeError沒有爲命名關鍵字參數height傳值。

命名關鍵字參數也可以有默認值(注意:這個不叫默認形參),從而簡化調用

>>> def register(name,age,*,sex='male',height):
	pass

如果形參中已經有一個*args了,命名關鍵字參數就不再需要一個單獨的*作爲分隔符號了,而是\*args作爲分隔符號,後面是命名關鍵字參數

>>> def register(name,age,*args,sex='male',height):#sex,height仍然爲命名關鍵字參數

有人可能還會問如果是**kwargs呢?是不是以**kwargs爲分隔符?

答:這樣會報錯,這樣也沒有什麼用,因爲**kwargs就是用來接收多餘的關鍵字實參的,如果多餘的不是關鍵字實參,會報錯。你再用命名關鍵字參數,限制必須關鍵字實參傳值,沒有意義。

在這裏插入圖片描述

5、組合使用

綜上所述所有參數可任意組合使用,但形參定義順序必須是:位置參數、默認參數、\*args、命名關鍵字參數、**kwargs.

實參的定義順序可以是:位置實參、*、關鍵字參數、**

func(111,*(333,444),y=222,**{'a':555,'b':666})
#只要*和**打散之後遵循位置實參在關鍵字參數左邊即可。*相當於一堆位置實參,**相當於一堆關鍵字參數

可變參數*args與關鍵字參數**kwargs通常是組合在一起使用的,如果一個函數的形參爲*args與**kwargs,那麼代表該函數可以接收任何形式、任意長度的參數

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

在該函數內部還可以把接收到的參數傳給另外一個函數(這在4.6小節裝飾器的實現中大有用處)

>>> def func(x,y,z):
...     print(x,y,z)
... 
>>> def wrapper(*args,**kwargs): #(1,)元組 {'z':3,'y':2}字典
...     func(*args,**kwargs) # *(1,) **{'z':3,'y':2},實參使用*和**,打散元組、字典
...
>>> wrapper(1,z=3,y=2)
1 2 3
提示: *args、**kwargs中的args和kwargs被替換成其他名字並無語法錯誤,但使用args、kwargs是約定俗成的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章