使用 *args 和 **kwargs 來調(diào)用函數(shù)那現(xiàn)在我們將看到怎樣使用*args和**kwargs 來調(diào)用一個(gè)函數(shù),。 假設(shè),你有這樣一個(gè)小函數(shù):
你可以使用*args或**kwargs來給這個(gè)小函數(shù)傳遞參數(shù),。 下面是怎樣做:
arg1: two arg2: 3 arg3: 5
arg1: 5 arg2: two arg3: 3 標(biāo)準(zhǔn)參數(shù)與*args,、**kwargs在使用時(shí)的順序 那么如果你想在函數(shù)里同時(shí)使用所有這三種參數(shù), 順序是這樣的:
什么時(shí)候使用它們?這還真的要看你的需求而定。 最常見的用例是在寫函數(shù)裝飾器的時(shí)候(會(huì)在另一章里討論),。 此外它也可以用來做猴子補(bǔ)丁(monkey patching),。猴子補(bǔ)丁的意思是在程序運(yùn)行時(shí)(runtime)修改某些代碼。 打個(gè)比方,你有一個(gè)類,里面有個(gè)叫g(shù)et_info的函數(shù)會(huì)調(diào)用一個(gè)API并返回相應(yīng)的數(shù)據(jù),。如果我們想測試它,可以把API調(diào)用替換成一些測試數(shù)據(jù),。例 如:
我敢肯定你也可以想象到一些其他的用例。 生成器(Generators)首先我們要理解迭代器(iterators),。根據(jù)維基百科,迭代器是一個(gè)讓程序員可以遍歷一個(gè)容器(特別是列表)的對(duì)象,。然而,一個(gè)迭代器在遍歷并讀取一個(gè)容器的數(shù)據(jù)元素時(shí),并不會(huì)執(zhí)行一個(gè)迭代。你可能有點(diǎn)暈了,那我們來個(gè)慢動(dòng)作,。換句話說這里有三個(gè)部分: 可迭代對(duì)象(Iterable) 迭代器(Iterator) 迭代(Iteration) 上面這些部分互相聯(lián)系,。我們會(huì)先各個(gè)擊破來討論他們,然后再討論生成器(generators). 可迭代對(duì)象(Iterable)Python中任意的對(duì)象,只要它定義了可以返回一個(gè)迭代器的__iter__方法,或者定義了可以支持下標(biāo)索引的__getitem__方法(這些雙下劃線方法會(huì)在其他章節(jié)中全面解釋),那么它就是一個(gè)可迭代對(duì)象。簡單說,可迭代對(duì)象就是能提供迭代器的任意對(duì)象,。那迭代器又是什么呢? 迭代器(Iterator)任意對(duì)象,只要定義了next(Python2) 或者_(dá)_next__方法,它就是一個(gè)迭代器,。就這么簡單。現(xiàn)在我們來理解迭代(iteration) 迭代(Iteration)用簡單的話講,它就是從某個(gè)地方如一個(gè)列表)取出一個(gè)元素的過程,。當(dāng)我們使用一個(gè)循環(huán)來遍歷某個(gè)東西時(shí),這個(gè)過程本身就叫迭代?,F(xiàn)在既然我們有了這些術(shù)語的基本理解,那我們開始理解生成器吧。 生成器(Generators)生成器也是一種迭代器,但是你只能對(duì)其迭代一次,。這是因?yàn)樗鼈儾]有把所有的值存在內(nèi)存中,而是在運(yùn)行時(shí)生成值,。你通過遍歷來使用它們,要么用一個(gè)“for”循環(huán),要么將它們傳遞給任意可以進(jìn)行迭代的函數(shù)和結(jié)構(gòu)。大多數(shù)時(shí)候生成器是以函數(shù)來實(shí)現(xiàn)的,。然而,它們并不返回一個(gè)值,而是yield(暫且譯作“生出”)一個(gè)值,。這里有個(gè)生成器函數(shù)的簡單例子:
這個(gè)案例并不是非常實(shí)用。生成器最佳應(yīng)用場景是:你不想同一時(shí)間將所有計(jì)算出來的大量結(jié)果集分配到內(nèi)存當(dāng)中,特別是結(jié)果集里還包含循環(huán),。 譯者注:這樣做會(huì)消耗大量資源 許多Python 2里的標(biāo)準(zhǔn)庫函數(shù)都會(huì)返回列表,而Python 3都修改成了返回生成器,因?yàn)樯善髡加酶俚馁Y源。 下面是一個(gè)計(jì)算斐波那契數(shù)列的生成器:
用這種方式,我們可以不用擔(dān)心它會(huì)使用大量資源,。然而,之前如果我們這樣來實(shí)現(xiàn)的話:
這也許會(huì)在計(jì)算很大的輸入?yún)?shù)時(shí),用盡所有的資源,。我們已經(jīng)討論過生成器使用一次迭代,但我們并沒有測試過。在測試前你需要再知道一個(gè)Python內(nèi)置函數(shù):next(),。它允許我們獲取一個(gè)序列的下一個(gè)元素,。那我們來驗(yàn)證下我們的理解:
我們可以看到,在yield掉所有的值后,next()觸發(fā)了一個(gè)StopIteration的異常?;旧线@個(gè)異常告訴我們,所有的值都已經(jīng)被yield完了,。你也許會(huì)奇怪,為什么我們?cè)谑褂胒or循環(huán)時(shí)沒有這個(gè)異常呢?啊哈,答案很簡單。for循環(huán)會(huì)自動(dòng)捕捉到這個(gè)異常并停止調(diào)用next(),。你知不知道Python中一些內(nèi)置數(shù)據(jù)類型也支持迭代哦?我們這就去看看:
好吧,這不是我們預(yù)期的,。這個(gè)異常說那個(gè)str對(duì)象不是一個(gè)迭代器,。對(duì),就是這樣!它是一個(gè)可迭代對(duì)象,而不是一個(gè)迭代器。這意味著它支持迭代,但我們不能直接對(duì)其進(jìn)行迭代操作,。那我們?cè)鯓硬拍軐?duì)它實(shí)施迭代呢?是時(shí)候?qū)W習(xí)下另一個(gè)內(nèi)置函數(shù),iter,。它將根據(jù)一個(gè)可迭代對(duì)象返回一個(gè)迭代器對(duì)象。這里是我們?nèi)绾问褂盟?#xff1a;
現(xiàn)在好多啦,。我肯定你已經(jīng)愛上了學(xué)習(xí)生成器,。一定要記住,想要完全掌握這個(gè)概念,你只有使用它。確保你按照這個(gè)模式,并在生成器對(duì)你有意義的任何時(shí)候都使用它,。你絕對(duì)不會(huì)失望的! |
|