Python 語言學習 第八篇:函式2(引數、lamdba和函式屬性)
函式的引數是引數暴露給外部的介面,向函式傳遞引數,可以控制函式的流程,函式可以0個、1個或多個引數;在Python中向函式傳參,使用的是賦值方式。
一,傳遞引數
引數是通過賦值來傳遞的,傳遞引數的特點是:
- 引數的傳遞是通過自動把物件賦值給函式的本地變數名來實現的,
- 在函式內部的變數名的賦值不會影響呼叫者,在函式執行時,在函式頭部的引數名是一個新的、本地的變數名,這個變數名的作用域是在函式的本地作用域內。
- 改變函式的可變物件引數的值,會修改原始物件的值。
當通過賦值方式,把可變物件的引用傳遞給函式時,在函式內部對引數進行修改,在函式外部可以看到修改。
例如,列表是一個可變物件,當把列表 a 傳遞給 changer函式時,函式向列表末尾新增一個字元a,當函式呼叫結束時,列表末尾被修改。
>>> def changer(x): ... x.append('a') ... >>> a=[1,2,3] >>> changer(a) >>> a [1, 2, 3, 'a']
這是由於可變物件是通過指標進行傳遞的,當把列表的引用傳遞給引數時,函式直接在原處修改物件。
也可以通過向引數傳遞拷貝的方式,使得函式無法修改原始的物件。
changer(a[:])
changer(a.copy())
二,引數匹配模型
不管使用何種引數的匹配模型,引數總是通過賦值進行傳遞的。
在預設情況下,引數是通過其位置進行匹配的,從左向右,而且必須精確地傳遞和函式頭部引數名一樣多的引數。還能夠通過引數名匹配,預設引數名,以及對於額外引數的容器來進行傳參。
1,位置匹配
一般情況下,引數是通過位置從左至右進行匹配,把引數傳遞給函式頭部的引數名稱。
例如,定義函式func,包含三個引數,那麼必須使用三個引數傳值進行呼叫:
def func(a,b,c):
呼叫的格式是,按照順序把值寫在括號中,Python按照位置匹配引數,把1賦值給a,把2賦值給b,把3賦值給c:
func(1,2,3)
2,關鍵字匹配
呼叫者使用arg_name=value的方式,通過在呼叫時使用引數的變數名進行匹配。
例如,定義引數func,包含三個引數,那麼必須使用三個引數傳值進行呼叫:
def func(x,y,z):
使用關鍵字呼叫的格式是:按照 arg=named的方式進行匹配,可以不按照位置:
func(y=2, x=1, z=3)
在呼叫函式時,Python按照引數名進行匹配,把2傳遞給引數y,把1傳遞給引數x,把3傳遞給引數z。
也可以混合使用位置匹配和關鍵字匹配,例如,下面的函式呼叫:
func(1,z=3,y=2)
基於位置的匹配引數,首先按照從左至右的順序匹配前面的引數,之後,再按照基於變數名進行關鍵字匹配。
3,預設引數
在定義函式時,可以為函式的引數賦值,這就是引數的預設值。當沒有為該引數傳值時,引數值使用預設值。
例如,定義一個函式,包含三個引數,x、y和z,其中引數z有預設值1:
def func(x,y,z=1):
當呼叫這個函式,必須為引數x和y傳值,無論是通過位置匹配還是關鍵字匹配來實現都可以。然而,引數z的傳值是可選的。如果不為z傳值,那麼z使用預設值;如果為z傳值,那麼z使用傳遞的值。
func(2,3)
4,可變長引數列表
可變引數用於收集任意多個基於位置或關鍵字的引數,在函式定義時,如果引數名前帶一個*號,那麼該引數收集的是基於位置的傳值;如果引數名前帶兩個*號(**arg),那麼該引數收集的是基於關鍵字(arg=value)的傳值。
def func(*args)
def func(**dict)
這兩種方式的不同點是,*args方式是把任意多個傳值封裝成元組(arg1,arg2),而**dict是把任意多個 arg=value 封裝成字典{arg:value},字典的key是引數名,字典key對應的值是引數的值。
例如,定義函式foo,包含一個位置匹配引數,1個可變的位置匹配引數,1個可變的關鍵字匹配引數:
def foo(a,*b,**c):
在呼叫函式時,首先按照位置匹配,把1傳遞給引數a,把元組(2,3)傳遞給引數b,把字典{x:1,y:2}傳遞給引數c:
foo(1,2,3,x=1,y=2)
5,只能使用關鍵字引數
引數必須按照名稱傳值,在函式定義時,引數必須在呼叫中按照關鍵字進行傳值:
def func(*,arg=value)
從語法上來講,keyword-only引數編碼為關鍵字引數,出現在引數列表的*args之後,所有這些引數都必須在呼叫中使用關鍵字語法來傳值。
def foo(a,*b,c):
在呼叫foo函式時,引數a可以按照位置和關鍵字來傳值,引數b接收按照其餘的按照位置來傳值的變數,引數c必須按照關鍵字來傳值:
foo(1,2,'a',3,c='key')
也可以在引數列表中使用一個*字元,來表示一個函式不會接受一個可變的引數列表,而是仍然期待跟在*後面的所有引數都作為關鍵字匹配。
例如,定義函式foo,只接受3個引數,不接受可變長度的引數列表:
def foo(a,*,b,c):
在呼叫時,引數a可以按照位置和關鍵字來傳值,引數b和c必須按照關鍵字來傳值:
foo(1,b='x',c=2)
三,lambda表示式
除了def語句之外,Python還提供了一種生成函式物件的表示式形式,lambda表示式。就像def語句一樣,這個表示式建立了一個函式物件,但是它返回了一個函式,而不是把這個函式賦值給一個變數名。
lambda表示式的一般形式是關鍵字lambda,之後是一個或多個引數(與一個def頭部內用括號括起來的引數列表極其類似),緊跟一個冒號,之後是一個表示式:
lambda arg1,arg2,... argN: expression_using_args
lambda表示式的特性是:
- lambda表示式返回的是函式物件;
- lambda是一個表示式,而不是一個語句,作為一個表示式,lambda返回了一個值(一個新的函式),可以選擇性地賦值給一個變數名;
- lambda的主體是一個單個的表示式,而不是一個程式碼塊,這個表示式的結果作為函式的結果返回。
lambda只有一行表示式,只能用於建立簡單的函式,而def 可以包含多條語句,用於處理複雜的任務。
對於簡單的處理流程,既可以使用def,也可以用lambda來實現,例如:
def func(x,y,z): return x+y+z func=lambda x,y,z: x+y+z
由於lambda表示式返回的是一個函式物件,因此,可以用於map()、filter()和reduce()函式中:
list(map((lambda x: x+3), range(0,5))) list(filter((lambda x: x>2), range(0,5))) from functools import reduce reduce((lambda x,y: x+y),range(0,5))
reduce()函式對每對元素都應用函式,並執行到最後結果,上述reduce()函式的作用是把序列中的所有元素相加,等價的寫法是:
x=list(range(0,5)] res=x[0] for i in x[1:] : res+=i
四,函式的屬性
可以向函式新增任意多個使用者定義的屬性,函式屬性的格式是:函式名稱.變數名
例如,向函式func中新增state屬性:
def func(): func.state='begin'
參考文件: