924|返回函數(shù)

函數(shù)作為返回值

高階函數(shù)除了可以接受函數(shù)作為參數(shù)外端圈,還可以把函數(shù)作為結(jié)果值返回。

我們來實現(xiàn)一個可變參數(shù)的求和舱权。通常情況下,求和的函數(shù)是這樣定義的:

def calc_sum(*args):
    ax = 0
    for n in args:
        ax = ax + n
    return ax

但是宴倍,如果不需要立刻求和,而是在后面的代碼中鸵贬,根據(jù)需要再計算怎么辦?可以不返回求和的結(jié)果阔逼,而是返回求和的函數(shù):

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

當我們調(diào)用lazy_sum()時兆衅,返回的并不是求和結(jié)果,而是求和函數(shù):


>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>

當我們調(diào)用lazy_sum()時嗜浮,返回的并不是求和結(jié)果羡亩,而是求和函數(shù):

>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>

調(diào)用函數(shù)f時,才真正計算求和的結(jié)果:

>>> f()
25

在這個例子中危融,我們在函數(shù)lazy_sum中又定義了函數(shù)sum畏铆,并且,內(nèi)部函數(shù)sum可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量吉殃,當lazy_sum返回函數(shù)sum時辞居,相關(guān)參數(shù)和變量都保存在返回的函數(shù)中,這種稱為“閉包(Closure)”的程序結(jié)構(gòu)擁有極大的威力寨腔。

請再注意一點速侈,當我們調(diào)用lazy_sum()時,每次調(diào)用都會返回一個新的函數(shù)迫卢,即使傳入相同的參數(shù):

>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False

f1()和f2()的調(diào)用結(jié)果互不影響倚搬。
返回函數(shù)

閱讀: 12732
函數(shù)作為返回值

高階函數(shù)除了可以接受函數(shù)作為參數(shù)外,還可以把函數(shù)作為結(jié)果值返回乾蛤。

我們來實現(xiàn)一個可變參數(shù)的求和每界。通常情況下,求和的函數(shù)是這樣定義的:

def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
但是家卖,如果不需要立刻求和眨层,而是在后面的代碼中,根據(jù)需要再計算怎么辦上荡?可以不返回求和的結(jié)果趴樱,而是返回求和的函數(shù):

def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
當我們調(diào)用lazy_sum()時馒闷,返回的并不是求和結(jié)果,而是求和函數(shù):

f = lazy_sum(1, 3, 5, 7, 9)
f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
調(diào)用函數(shù)f時叁征,才真正計算求和的結(jié)果:

f()
25
在這個例子中纳账,我們在函數(shù)lazy_sum中又定義了函數(shù)sum,并且捺疼,內(nèi)部函數(shù)sum可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量疏虫,當lazy_sum返回函數(shù)sum時,相關(guān)參數(shù)和變量都保存在返回的函數(shù)中啤呼,這種稱為“閉包(Closure)”的程序結(jié)構(gòu)擁有極大的威力卧秘。

請再注意一點,當我們調(diào)用lazy_sum()時官扣,每次調(diào)用都會返回一個新的函數(shù)翅敌,即使傳入相同的參數(shù):

f1 = lazy_sum(1, 3, 5, 7, 9)
f2 = lazy_sum(1, 3, 5, 7, 9)
f1==f2
f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>

當我們調(diào)用lazy_sum()時,返回的并不是求和結(jié)果惕蹄,而是求和函數(shù):
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
調(diào)用函數(shù)f時哼御,才真正計算求和的結(jié)果:
>>> f()
25
在這個例子中焊唬,我們在函數(shù)lazy_sum中又定義了函數(shù)sum看靠,并且挟炬,內(nèi)部函數(shù)sum可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量,當lazy_sum返回函數(shù)sum時婿滓,相關(guān)參數(shù)和變量都保存在返回的函數(shù)中凸主,這種稱為“閉包(Closure)”的程序結(jié)構(gòu)擁有極大的威力额湘。 請再注意一點,當我們調(diào)用lazy_sum()時嗡官,每次調(diào)用都會返回一個新的函數(shù)衍腥,即使傳入相同的參數(shù):
>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False
```
f1()和f2()的調(diào)用結(jié)果互不影響婆咸。
返回函數(shù)

閱讀: 12732
函數(shù)作為返回值

高階函數(shù)除了可以接受函數(shù)作為參數(shù)外,還可以把函數(shù)作為結(jié)果值返回活孩。

我們來實現(xiàn)一個可變參數(shù)的求和憾儒。通常情況下乃沙,求和的函數(shù)是這樣定義的:

def calc_sum(args):
ax = 0
for n in args:
ax = ax + n
return ax
但是警儒,如果不需要立刻求和,而是在后面的代碼中边琉,根據(jù)需要再計算怎么辦变姨?可以不返回求和的結(jié)果厌丑,而是返回求和的函數(shù):

def lazy_sum(
args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
當我們調(diào)用lazy_sum()時怒竿,返回的并不是求和結(jié)果,而是求和函數(shù):

>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
調(diào)用函數(shù)f時爷辱,才真正計算求和的結(jié)果:

>>> f()
25
在這個例子中托嚣,我們在函數(shù)lazy_sum中又定義了函數(shù)sum厚骗,并且领舰,內(nèi)部函數(shù)sum可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量迟螺,當lazy_sum返回函數(shù)sum時矩父,相關(guān)參數(shù)和變量都保存在返回的函數(shù)中窍株,這種稱為“閉包(Closure)”的程序結(jié)構(gòu)擁有極大的威力攻柠。

請再注意一點瑰钮,當我們調(diào)用lazy_sum()時,每次調(diào)用都會返回一個新的函數(shù)开睡,即使傳入相同的參數(shù):

>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False
f1()和f2()的調(diào)用結(jié)果互不影響篇恒。

閉包

注意到返回的函數(shù)在其定義內(nèi)部引用了局部變量args凶杖,所以官卡,當一個函數(shù)返回了一個函數(shù)后寻咒,其內(nèi)部的局部變量還被新函數(shù)引用颈嚼,所以阻课,閉包用起來簡單,實現(xiàn)起來可不容易抹恳。

另一個需要注意的問題是署驻,返回的函數(shù)并沒有立刻執(zhí)行健霹,而是直到調(diào)用了f()才執(zhí)行糖埋。我們來看一個例子:

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()

在上面的例子中窃这,每次循環(huán)杭攻,都創(chuàng)建了一個新的函數(shù),然后垒棋,把創(chuàng)建的3個函數(shù)都返回了痪宰。

你可能認為調(diào)用f1(),f2()和f3()結(jié)果應該是1乖订,4乍构,9扛点,但實際結(jié)果是:

>>> f1()
9
>>> f2()
9
>>> f3()
9

全部都是9!原因就在于返回的函數(shù)引用了變量i眠饮,但它并非立刻執(zhí)行铜邮。等到3個函數(shù)都返回時松蒜,它們所引用的變量i已經(jīng)變成了3,因此最終結(jié)果為9召娜。

返回閉包時牢記的一點就是:返回函數(shù)不要引用任何循環(huán)變量惊楼,或者后續(xù)會發(fā)生變化的變量。

如果一定要引用循環(huán)變量怎么辦店读?方法是再創(chuàng)建一個函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當前的值文虏,無論該循環(huán)變量后續(xù)如何更改殖演,已綁定到函數(shù)參數(shù)的值不變:


def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被執(zhí)行趴久,因此i的當前值被傳入f()
    return fs

再看看結(jié)果:

>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

缺點是代碼較長,可利用lambda函數(shù)縮短代碼灭忠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弛作,一起剝皮案震驚了整個濱河市映琳,隨后出現(xiàn)的幾起案子萨西,更是在濱河造成了極大的恐慌,老刑警劉巖谎脯,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異际看,居然都是意外死亡矢否,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門屑彻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人社牲,你說我怎么就攤上這事悴了。” “怎么了熟空?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵息罗,是天一觀的道長迈喉。 經(jīng)常有香客問我糜工,道長,這世上最難降的妖魔是什么油坝? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任澈圈,我火速辦了婚禮瞬女,結(jié)果婚禮上努潘,老公的妹妹穿的比我還像新娘疯坤。我一直安慰自己,他們只是感情好眠冈,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布蜗顽。 她就那樣靜靜地躺著雇盖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪这弧。 梳的紋絲不亂的頭發(fā)上虚汛,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天卷哩,我揣著相機與錄音将谊,去河邊找鬼。 笑死逞频,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的栋齿。 我是一名探鬼主播瓦堵,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼菇用,長吁一口氣:“原來是場噩夢啊……” “哼惋鸥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耐量,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤拴鸵,失蹤者是張志新(化名)和其女友劉穎蜗搔,沒想到半個月后劲藐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡樟凄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年聘芜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缝龄。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡汰现,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叔壤,到底是詐尸還是另有隱情瞎饲,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布炼绘,位于F島的核電站嗅战,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏俺亮。R本人自食惡果不足惜东且,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一旨椒、第九天 我趴在偏房一處隱蔽的房頂上張望综慎。 院中可真熱鬧,春花似錦、人聲如沸录择。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至京痢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間臣淤,已是汗流浹背按厘。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工懒棉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓怀各,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容