摘要:到這里,如果你明白了,我們就可以繼續進行下一步了理解匿名函數。
似乎只要一沾上for循環,難度立刻加倍,下面我們來看一道python的面試題:
要求寫出下面代碼的輸出結果并且解釋原因。
def multipliers(): return [lambda x:i*x for i in range(4)] print([m(2) for m in multipliers()])
這道題涉及的知識點包括以下幾個方面:
1、列表推導式 2、匿名函數 3、閉包函數 4、for循環對函數的迭代調用 5、閉包函數的調用
首先我們來說一下列表推導式,只有深入理解列表推導式,我們才能理解下面這句話到底干了些什么事情[lambda x:i*x for i in range(4)]
引用官方文檔中對于列表推導式的一個例子:squares = [x2 for x in range(10)] 這個列表推導式返回的結果為[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],for循環通過對range(10)進行迭代后得到每個x的值,然后對它進執行x2的操作,最終結果為一個列表
那么如果不用列表推導式如何達到這個目的呢?答案如下,這個列表推導式等同于下面的代碼:
squares = [] for x in range(10): squares.append(x**2)
這段代碼執行后,squares的結果一樣是[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],根據這個例子我們可以簡單地認為列表推導式是這樣工作的:首先它會定義一個空列表,然后根據設定的條件得到一個一個的元素,同時把元素添加進列表中。
現在回到我們這道題,來看一下本題中的[lambda x:i*x for i in range(4)]這個列表推導式,如果把它拆開來的話它等價于下面的這段代碼:
squares = [] for i in range(4): res = lambda x:i*x squares.append(res)
最終squares就是列表推導式的結果(一個列表),然后我們再研究下這個列表中的元素都是什么。
到這里,如果你明白了,我們就可以繼續進行下一步了——理解匿名函數。
匿名函數的關鍵字為lambda,表現形式為:lambda 參數 : 返回值,lambda后面的參數就是函數的形參,冒號后面的表達式就是返回值。
比如:lambda a, b: a+b 這個簡單的匿名函數可以傳入兩個參數a和b,結果返回a+b,這里要記住,只有調用這個匿名函數,它才會執行冒號后面的代碼,這也是函數的執行法則,只有被調用時,函數內部的命名空間才會生效,在被調用之前它就是一個函數名指向的內存地址而已。
匿名函數雖然是匿名的,但是它也可以有名字,也可以作為一個結果賦值給任意的變量,所以它顯然可以成為一個函數的返回值,也可以變成一個列表的元素,只不過此時這個列表的元素是匿名函數對應的內存地址罷了。見下面的例子:
#匿名函數直接賦值給變量lam lam = lambda a,b:a+b #此時lam指向了匿名函數的內存地址 print(lam)#此時的lam就是一個內存地址:at 0x7fecdc6b7e18> res = lam(2,5) #調用匿名函數,把結果賦值給res print(res)
at 0x7fecdc6b7e18> 7
接下來我們說一下閉包,當前函數引用到上一層函數的局部命名空間的變量時就會觸發閉包規則。我們說觸發了閉包的函數叫做閉包函數,但是要注意一點:只有當調用閉包函數的時候它才會去引用外層函數的變量,因為在調用閉包函數之前,閉包內部的命名空間還不存在。
然后我們回頭看這道題的代碼:
def multipliers(): return [lambda x:i*x for i in range(4)] print([m(2) for m in multipliers()]) #根據前面的敘述,我們可以把它改成容易理解的形式: def multipliers(): squares = [] for i in range(4): res = lambda x:i*x squares.append(res) return squares print([m(2) for m in multipliers()])
匿名函數lambda x:i*x引用了外層函數multipliers()的命名空間內的變量i,所以它觸發了閉包規則,然后函數multipliers()的返回值是一個列表,這個列表的元素為四個閉包函數名指向的內存地址,雖然for i in range(4)這段代碼里面的i的值分別被賦予了 0 1 2 3這四個值,但是閉包函數res并沒有引用這四個值,因為閉包函數此時此刻還沒有被真正調用,列表推導式僅僅是把四個匿名函數指向的內存地址保存在了一個列表里,因為沒有調用,所以匿名函數內部的代碼并沒有執行,也就不存在引用。
所以函數multipliers()的返回值就是這樣的一個列表:[lambda x:ix,lambda x:ix,lambda x:ix,lambda x:ix]
我們來看最后一條語句print([m(2) for m in multipliers()])
for m in multipliers() 這條語句到底干了什么?其實它干的事情只有一個,那就是遍歷了函數multipliers()返回的列表,在遍歷列表的同時把每個匿名函數賦值給了m,把它拆分來看就是這樣:
m = lambda x:i*x
m = lambda x:i*x
m = lambda x:i*x
m = lambda x:i*x
并且每次都執行了一次 m(2),也就是每次都調用了一下匿名函數,注意:此時此刻匿名函數才真正被調用了,然后它會引用外層命名空間的變量i,那么此時i的值是多少呢?
因為for i in range(4)這個for循環已經執行完畢,i的值等于3,所以每次當執行m(2)時,i的值都等于3
所以每次調用m(2)的結果都是6
最終輸出結果為[6, 6, 6, 6]
def multipliers(): return [lambda x:i*x for i in range(4)] print([m(2) for m in multipliers()])
[6, 6, 6, 6]把這道面試題中的所有列表推導式拆開的話 它應該是下面這個樣子,結果完全一樣:
def multipliers(): squares = [] for i in range(4): res = lambda x:i*x squares.append(res) return squares #print(multipliers()),此時此刻如果我們打印一下這個函數,也就是調用一下看看返回結果,你會發現,它就是一個由四個函數內存地址組成的列表: """[. at 0x7fecdc6de2f0>, . at 0x7fecdc6de510>, . at 0x7fecdc6de158>, . at 0x7fecdc6de268>]""" squares2 = [] for m in multipliers(): squares2.append(m(2)) print(squares2)
[6, 6, 6, 6]
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42558.html
摘要:這是一道魔性面試題,難倒了無數英雄好漢上面代碼的執行順序是這樣的從上到下第一個函數就是實現了一個簡單的加法運算第二個函數是一個生成器函數,如果調用它會返回一個生成器這一行調用了生成器函數,所以此刻就是一個生成器它的本質還是迭代器然后執行循環 這是一道魔性面試題,難倒了無數英雄好漢…… def add(n,i): return n+i def test(): for i...
摘要:昨天晚上,筆者有幸參加了一場面試,有一個環節就是現場編程題目如下示例數據如下,求每名學生對應的成績最高的那門科目與,用實現這個題目看上去很簡單,其實,并不簡單。 ??昨天晚上,筆者有幸參加了一場面試,有一個環節就是現場編程!題目如下:??示例數據如下,求每名學生(ID)對應的成績(score)最高的那門科目(class)與ID,用Python實現: showImg(https://se...
摘要:閉包正確的說應該是指一個閉包域每當聲明了一個函數它就產生了一個閉包域可以解釋為每個函數都有自己的函數棧每個閉包域對象都有一個不是屬性內默認有個名為的全局引用有了這個引用就可以直接調用的屬性或方法凡是在閉包域內聲明的變量或方法外部無法直接訪問 閉包 正確的說,應該是指一個閉包域,每當聲明了一個函數,它就產生了一個閉包域(可以解釋為每個函數都有自己的函數棧),每個閉包域(Function...
摘要:這是我在一次面試中,被面試官所提問的一道題在這次面試題中相等指的是對象的屬性個數值相等有這樣兩個李德華張德華我能想到的一種方案解答過程的思考由于沒有,我只能通過轉化成數組進入第二步,對象中的屬性在另一個中是否存在。 這是我在一次面試中,被面試官所提問的一道題 在這次面試題中 相等:指的是對象的屬性個數值相等 有這樣兩個obj let obj1 = { name:李德華, ...
摘要:收集的一些前端面試題從面試題發現不足,進而查漏補缺,比通過面試更難得及各大互聯網公司前端筆試面試題篇及各大互聯網公司前端筆試面試題篇面試題個和個經典面試題前端開發面試題如何面試前端工程師很重要個變態題解析如何通過餓了么面試輕 收集的一些前端面試題 從面試題發現不足,進而查漏補缺,比通過面試更難得 1 BAT及各大互聯網公司2014前端筆試面試題--Html,Css篇 2 BAT...
閱讀 2054·2021-10-08 10:04
閱讀 3079·2021-09-22 10:02
閱讀 2226·2019-08-30 15:56
閱讀 825·2019-08-30 15:54
閱讀 921·2019-08-30 15:54
閱讀 1276·2019-08-30 15:53
閱讀 2508·2019-08-30 11:21
閱讀 3557·2019-08-30 10:56