Python 函數(shù)參數(shù)之不定長參數(shù)(*args/**kwargs)辫樱、匿名函數(shù) Lambda詳解


Python?調(diào)用函數(shù)時可使用的正式參數(shù)類型:

? ??必需參數(shù) (位置參數(shù))峭拘、關(guān)鍵字參數(shù) (key=value)、默認(rèn)參數(shù) (key=default)狮暑、不定長參數(shù)(可變參數(shù))鸡挠、強制位置參數(shù)(組合傳參)

? ??Tips:有興趣的還可以了解一下什么是形參?什么是實參搬男?

不定長參數(shù)? *args **kwargs

? ? Python 在定義函數(shù)的過程中拣展,當(dāng)你可能需要一個函數(shù)能處理比當(dāng)初聲明時更多的參數(shù)。那么就會用到 *arg缔逛、**kwargs 稱之為不定長參數(shù)备埃,聲明時不會命名;

? ? *args 具體語法操作如下:

def func(a, *args):
????print(a)
????print(args)

func(1, 2)

結(jié)果輸出:
1
(2,)

注意:加了星號?*?的參數(shù)會以元組(tuple)的形式導(dǎo)入译株,存放所有未命名的變量參數(shù)瓜喇。?

如果在函數(shù)調(diào)用時沒有指定參數(shù),它就是一個空元組:

def func(a, *args):
?????print(a)
?????print(args)

func(10)
func(1, 2)

結(jié)果輸出:

結(jié)果:
10
()
結(jié)果:
1
(2,)

從上面的示例來看歉糜,如果傳入的參數(shù)超過了位置參數(shù)乘寒,后面的參數(shù)都會以元組的來接收,那么如果我們直接傳入一個元組參數(shù)行不行匪补?

t = (1, 2, 3)
def func(a, *args):
?????print('結(jié)果:')
?????print(a)
?????print(args)

func(1, 2, t )

結(jié)果:
1
(2, (1, 2, 3))

從以上示例來看目前是可以的伞辛,但是如果我們需要對參數(shù)進(jìn)行計算或者其他操作的時候呢?下面再來看一個列子:

t = (1, 2, 3)
def avg(a, *args):
?????return (a + sum(args)) / (len(args) + 1)

print(avg(20, t))

結(jié)果:

????TypeError: unsupported operand type(s) for +: 'int' and 'tuple'

結(jié)果就報錯了夯缺,原因是因為你直接傳入的是一個元組蚤氏,int類型和元組是不能直接進(jìn)行計算的,那么怎么解決這個問題踊兜?其實很簡單看下面的實例:

t = (1, 2, 3)
def avg(a, *args):??????
????return (a + sum(args)) / (len(args) + 1)

print(avg(20, *t))

結(jié)果:???

6.5

其實很簡單竿滨,只需要在傳 t 元組的時候加上一個 * 就可以了,稱之為解包捏境,就是把元組打散于游,分開傳入.


*kwargs 具體語法操作如下:

d = {'name': 'amy', 'age': 18}
t = (1, 2, 3)

def func(a, *args, **kwargs):
?????print('結(jié)果:')
?????print(f'位置參數(shù):{a}')
?????print(f'不定長元組參數(shù):{args}')
?????print(f'不定長鍵值對參數(shù):{kwargs}')

func(1, t, d)

結(jié)果:
位置參數(shù):1
不定長元組參數(shù):((1, 2, 3), {'name': 'amy', 'age': 18})
不定長鍵值對參數(shù):{}

咦,發(fā)現(xiàn)實際結(jié)果并不是我們想要的垫言,鍵值對的參數(shù)跑到元組里面去了贰剥,那下面看一下正確的傳入方式:

t = (1, 2, 3)

def func(a, *args, **kwargs):? ? ?
????print('結(jié)果:')??????
????print(f'位置參數(shù):{a}')??????
????print(f'不定長元組參數(shù):{args}')??????
????print(f'不定長鍵值對參數(shù):{kwargs}')

func(1, t, name='angst', age=18)?

結(jié)果:
位置參數(shù):1
不定長元組參數(shù):((1, 2, 3),)
不定長鍵值對參數(shù):{'name': 'angst', 'age': 18}

正確的參數(shù)傳入方式就是通過關(guān)鍵字參數(shù)的方式進(jìn)行傳入,這樣就達(dá)到了我們想要的目的筷频,但是蚌成,如果我就是想傳入一個字典類型的參數(shù)進(jìn)去怎么辦前痘?

d = {'name': 'amy', 'age': 18}
t = (1, 2, 3)

def func(a, *args, **kwargs):
?????print('結(jié)果:')
?????print(f'位置參數(shù):{a}')
?????print(f'不定長元組參數(shù):{args}')
?????print(f'不定長鍵值對參數(shù):{kwargs}')

func(1, t, **d)

結(jié)果:
位置參數(shù):1
不定長元組參數(shù):((1, 2, 3),)
不定長鍵值對參數(shù):{'name': 'amy', 'age': 18}

其實也是可以的,方法跟元組的類似担忧,參數(shù)在傳入的時候加上 ** 就行了芹缔。那么最后一個問題?怎么獲取對應(yīng)不定長參數(shù)的值呢瓶盛?

d = {'name': 'amy', 'age': 18}
t = (1, 2, 3)

def func(a, *args, **kwargs):
????print('結(jié)果:')
????print(f'位置參數(shù):{a}')
????print(f'不定長元組第一個參數(shù):{args[0][0]}')
????print(f'不定長鍵值對名稱參數(shù):{kwargs.get("name")}')

func(1, t, **d)

結(jié)果:
位置參數(shù):1
不定長元組第一個參數(shù):1
不定長鍵值對名稱參數(shù):amy

從上面的列子可以看出乖菱,其實獲取的并沒有什么不同,元組通過下標(biāo)獲取蓬网,字典通過Key獲取窒所。



匿名函數(shù)??Lambda?

python 使用 lambda 來創(chuàng)建匿名函數(shù)。所謂匿名帆锋,意即不再使用 def 語句這樣標(biāo)準(zhǔn)的形式定義一個函數(shù)吵取。簡單來說就是不用給函數(shù)定義名稱;

? ?> lambda 只是一個表達(dá)式锯厢,函數(shù)體比 def 簡單很多皮官。

? ? >lambda的主體是一個表達(dá)式,而不是一個代碼塊实辑。僅僅能在lambda表達(dá)式中封裝有限的邏輯進(jìn)去捺氢。

? ? >lambda 函數(shù)擁有自己的命名空間,且不能訪問自己參數(shù)列表之外或全局命名空間里的參數(shù)剪撬。

? ? >雖然lambda函數(shù)看起來只能寫一行摄乒,卻不等同于C或C++的內(nèi)聯(lián)函數(shù),后者的目的是調(diào)用小函數(shù)時不占用棧內(nèi)存從而增加運行效率

以上是 菜鳥教程 的解釋残黑,下面來看具體的示例:

def hello(name):
?????print(f'hello {name}')

hello('Amy')

angst = lambda name: print(f'hello {name}')

print(angst)

結(jié)果輸出:
hello Amy
<function <lambda> at 0x0000026EE6F34048>

????一個是正常的 hello() 函數(shù)定義和調(diào)用馍佑,又定義了一個lambda 函數(shù)賦值給了變量 angst,兩個函數(shù)的實際功能其實是一直的,但是從上面輸出的結(jié)果來看 angst 出輸出的是一個函數(shù)對象在內(nèi)存的地址梨水;其實并沒有調(diào)用拭荤,只是打印了angst 函數(shù)變量而已,正確的調(diào)用方式其實跟正常的函數(shù)一樣疫诽,在變量后面加上一個()

def hello(name):
????print(f'hello {name}')

hello('Amy')

angst = lambda name: print(f'hello {name}')

angst('angst')

結(jié)果輸出:
hello Amy
hello angst

? ? 從上面可以看出舅世,其實匿名函數(shù)從本質(zhì)上來說并沒有不同,只是使用的場景稍微有些特許而已奇徒,由于lambda 函數(shù)沒有定義名稱雏亚,所有我們在定義的時候通過會賦值一個變量去引用,之前的變量一般都是一些參數(shù)類型逼龟,但是通過lambda的形式將函數(shù)賦值給變量评凝,通過變量調(diào)用該函數(shù)時需要帶上(),如果有參數(shù)就在()傳參即可追葡。lambda 的函數(shù)一般是用于比較簡單的函數(shù)表達(dá)腺律。lambda 函數(shù)還有一個特性就是自帶 return 關(guān)鍵字奕短,可以自動把結(jié)果返回給函數(shù)本身。

lambda:None匀钧;函數(shù)沒有輸入?yún)?shù)翎碑,輸出是 None?
lambda x, y: x+y;函數(shù)輸入是x和y之斯,輸出是它們的和
lambda *args: sum(args); 輸入是任意個數(shù)的參數(shù)日杈,輸出是它們的和(隱性要求是輸入?yún)?shù)必須能夠進(jìn)行加法運算)
lambda **kwargs: kwagrs.get(key);輸入是任意鍵值對參數(shù)佑刷,輸出是key 對應(yīng)的value

? ??根據(jù)這個lambda函數(shù)應(yīng)用場景的不同莉擒,可以將lambda函數(shù)的用法有以下幾種 參考博客

? ? 1>.將lambda函數(shù)賦值給一個變量,通過這個變量間接調(diào)用該lambda函數(shù),調(diào)用時記得帶上()

????2>.將lambda函數(shù)賦值給其他函數(shù)瘫絮,從而將其他函數(shù)用該 lambda 函數(shù)進(jìn)行替換.
? ? ? ? 例:time.sleep=lambda x:None涨冀,在后續(xù)代碼中調(diào)用time庫的sleep函數(shù)將不會執(zhí)行原有的功能。執(zhí)行time.sleep(3)時麦萤,不會休眠3秒而是None

? ? 3>.將lambda函數(shù)作為其他函數(shù)的返回值鹿鳖,返回給調(diào)用者
????????例如:return lambda x, y: x+y 返回一個加法函數(shù)。lambda函數(shù)實際上是定義在某個函數(shù)內(nèi)部的函數(shù)壮莹,稱之為嵌套函數(shù)翅帜,或者內(nèi)部函數(shù)。對應(yīng)的命满,將包含嵌套函數(shù)的函數(shù)稱之為外部函數(shù)涝滴。內(nèi)部函數(shù)能夠訪問外部函數(shù)的局部變量,這個特性是閉包(Closure)編程的基礎(chǔ)胶台,在后面的高級教程裝飾器中會用到狭莱,這里就不描述具體的用法了,后續(xù)可以關(guān)注我的博客概作,有專門對陣裝飾器的用法講解腋妙。

????4>.將lambda函數(shù)作為參數(shù)傳遞給其他函數(shù)
? ? ? ? 例:部分Python內(nèi)置函數(shù)接收函數(shù)作為參數(shù)。map函數(shù):lambda函數(shù)用于指定對列表中每一個元素的共同操作讯榕。如:map(lambda x: x+1, [1, 2,3])將列表[1, 2, ????????3]中的元素分別加1骤素,其結(jié)果[2, 3, 4]

????lambda的使用一直存在一些爭議,lambda 函數(shù)的好處和局限都很明顯愚屁,到底要不要使用和什么使用需要自我實踐了济竹,只要在合理的時候使用合理的操作才是最合理的。

以上就是匿名函數(shù)的一些常用操作霎槐,當(dāng)然還有更多的高級用法送浊,有興趣的同學(xué)可以自行查閱資料。如果有疑問也可以給我留言丘跌。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末袭景,一起剝皮案震驚了整個濱河市唁桩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌耸棒,老刑警劉巖荒澡,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異与殃,居然都是意外死亡单山,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門幅疼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來米奸,“玉大人,你說我怎么就攤上這事爽篷□锷” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵狼忱,是天一觀的道長膨疏。 經(jīng)常有香客問我,道長钻弄,這世上最難降的妖魔是什么佃却? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮窘俺,結(jié)果婚禮上饲帅,老公的妹妹穿的比我還像新娘。我一直安慰自己瘤泪,他們只是感情好灶泵,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著对途,像睡著了一般赦邻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上实檀,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天惶洲,我揣著相機與錄音,去河邊找鬼膳犹。 笑死恬吕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的须床。 我是一名探鬼主播铐料,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了钠惩?” 一聲冷哼從身側(cè)響起柒凉,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妻柒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耘分,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡举塔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了求泰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片央渣。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖渴频,靈堂內(nèi)的尸體忽然破棺而出芽丹,到底是詐尸還是另有隱情,我是刑警寧澤卜朗,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布拔第,位于F島的核電站,受9級特大地震影響场钉,放射性物質(zhì)發(fā)生泄漏蚊俺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一逛万、第九天 我趴在偏房一處隱蔽的房頂上張望泳猬。 院中可真熱鬧,春花似錦宇植、人聲如沸得封。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忙上。三九已至,卻和暖如春闲坎,著一層夾襖步出監(jiān)牢的瞬間晨横,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工箫柳, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留手形,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓悯恍,卻偏偏與公主長得像库糠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354