1. 程式人生 > >Python 語言學習 第八篇:函式2(引數、lamdba和函式屬性)

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'

 

參考文件: