国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

python面試題之“該死的for循環(huán)系列”(二)

shiweifu / 526人閱讀

摘要:到這里,如果你明白了,我們就可以繼續(xù)進(jìn)行下一步了理解匿名函數(shù)。

似乎只要一沾上for循環(huán),難度立刻加倍,下面我們來看一道python的面試題:

要求寫出下面代碼的輸出結(jié)果并且解釋原因。

def multipliers():
    return [lambda x:i*x for i in range(4)]
print([m(2) for m in multipliers()])

這道題涉及的知識點包括以下幾個方面:

1、列表推導(dǎo)式
2、匿名函數(shù)
3、閉包函數(shù)
4、for循環(huán)對函數(shù)的迭代調(diào)用
5、閉包函數(shù)的調(diào)用

首先我們來說一下列表推導(dǎo)式,只有深入理解列表推導(dǎo)式,我們才能理解下面這句話到底干了些什么事情[lambda x:i*x for i in range(4)]
引用官方文檔中對于列表推導(dǎo)式的一個例子:squares = [x2 for x in range(10)] 這個列表推導(dǎo)式返回的結(jié)果為[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],for循環(huán)通過對range(10)進(jìn)行迭代后得到每個x的值,然后對它進(jìn)執(zhí)行x2的操作,最終結(jié)果為一個列表
那么如果不用列表推導(dǎo)式如何達(dá)到這個目的呢?答案如下,這個列表推導(dǎo)式等同于下面的代碼:

squares = []
for x in range(10):
    squares.append(x**2)

這段代碼執(zhí)行后,squares的結(jié)果一樣是[0, 1, 4, 9, 16, 25, 36, 49, 64, 81],根據(jù)這個例子我們可以簡單地認(rèn)為列表推導(dǎo)式是這樣工作的:首先它會定義一個空列表,然后根據(jù)設(shè)定的條件得到一個一個的元素,同時把元素添加進(jìn)列表中。

現(xiàn)在回到我們這道題,來看一下本題中的[lambda x:i*x for i in range(4)]這個列表推導(dǎo)式,如果把它拆開來的話它等價于下面的這段代碼:

squares = []
for i in range(4):
    res = lambda x:i*x
    squares.append(res)

最終squares就是列表推導(dǎo)式的結(jié)果(一個列表),然后我們再研究下這個列表中的元素都是什么。
到這里,如果你明白了,我們就可以繼續(xù)進(jìn)行下一步了——理解匿名函數(shù)。

匿名函數(shù)的關(guān)鍵字為lambda,表現(xiàn)形式為:lambda 參數(shù) : 返回值,lambda后面的參數(shù)就是函數(shù)的形參,冒號后面的表達(dá)式就是返回值。
比如:lambda a, b: a+b 這個簡單的匿名函數(shù)可以傳入兩個參數(shù)a和b,結(jié)果返回a+b,這里要記住,只有調(diào)用這個匿名函數(shù),它才會執(zhí)行冒號后面的代碼,這也是函數(shù)的執(zhí)行法則,只有被調(diào)用時,函數(shù)內(nèi)部的命名空間才會生效,在被調(diào)用之前它就是一個函數(shù)名指向的內(nèi)存地址而已。

匿名函數(shù)雖然是匿名的,但是它也可以有名字,也可以作為一個結(jié)果賦值給任意的變量,所以它顯然可以成為一個函數(shù)的返回值,也可以變成一個列表的元素,只不過此時這個列表的元素是匿名函數(shù)對應(yīng)的內(nèi)存地址罷了。見下面的例子:

#匿名函數(shù)直接賦值給變量lam
lam = lambda a,b:a+b
#此時lam指向了匿名函數(shù)的內(nèi)存地址
print(lam)#此時的lam就是一個內(nèi)存地址: at 0x7fecdc6b7e18>
res = lam(2,5) #調(diào)用匿名函數(shù),把結(jié)果賦值給res
print(res)
 at 0x7fecdc6b7e18>
7

接下來我們說一下閉包,當(dāng)前函數(shù)引用到上一層函數(shù)的局部命名空間的變量時就會觸發(fā)閉包規(guī)則。我們說觸發(fā)了閉包的函數(shù)叫做閉包函數(shù),但是要注意一點:只有當(dāng)調(diào)用閉包函數(shù)的時候它才會去引用外層函數(shù)的變量,因為在調(diào)用閉包函數(shù)之前,閉包內(nèi)部的命名空間還不存在。

然后我們回頭看這道題的代碼:

def multipliers():
    return [lambda x:i*x for i in range(4)]
print([m(2) for m in multipliers()])
#根據(jù)前面的敘述,我們可以把它改成容易理解的形式:
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()])

匿名函數(shù)lambda x:i*x引用了外層函數(shù)multipliers()的命名空間內(nèi)的變量i,所以它觸發(fā)了閉包規(guī)則,然后函數(shù)multipliers()的返回值是一個列表,這個列表的元素為四個閉包函數(shù)名指向的內(nèi)存地址,雖然for i in range(4)這段代碼里面的i的值分別被賦予了 0 1 2 3這四個值,但是閉包函數(shù)res并沒有引用這四個值,因為閉包函數(shù)此時此刻還沒有被真正調(diào)用,列表推導(dǎo)式僅僅是把四個匿名函數(shù)指向的內(nèi)存地址保存在了一個列表里,因為沒有調(diào)用,所以匿名函數(shù)內(nèi)部的代碼并沒有執(zhí)行,也就不存在引用。
所以函數(shù)multipliers()的返回值就是這樣的一個列表:[lambda x:ix,lambda x:ix,lambda x:ix,lambda x:ix]

我們來看最后一條語句print([m(2) for m in multipliers()])
for m in multipliers() 這條語句到底干了什么?其實它干的事情只有一個,那就是遍歷了函數(shù)multipliers()返回的列表,在遍歷列表的同時把每個匿名函數(shù)賦值給了m,把它拆分來看就是這樣:
m = lambda x:i*x
m = lambda x:i*x
m = lambda x:i*x
m = lambda x:i*x
并且每次都執(zhí)行了一次 m(2),也就是每次都調(diào)用了一下匿名函數(shù),注意:此時此刻匿名函數(shù)才真正被調(diào)用了,然后它會引用外層命名空間的變量i,那么此時i的值是多少呢?
因為for i in range(4)這個for循環(huán)已經(jīng)執(zhí)行完畢,i的值等于3,所以每次當(dāng)執(zhí)行m(2)時,i的值都等于3
所以每次調(diào)用m(2)的結(jié)果都是6
最終輸出結(jié)果為[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]

把這道面試題中的所有列表推導(dǎo)式拆開的話 它應(yīng)該是下面這個樣子,結(jié)果完全一樣:
def multipliers():
    squares = []
    for i in range(4):
        res = lambda x:i*x
        squares.append(res)
    return squares

#print(multipliers()),此時此刻如果我們打印一下這個函數(shù),也就是調(diào)用一下看看返回結(jié)果,你會發(fā)現(xiàn),它就是一個由四個函數(shù)內(nèi)存地址組成的列表:
"""[. at 0x7fecdc6de2f0>, 
 . at 0x7fecdc6de510>, 
 . at 0x7fecdc6de158>, 
 . at 0x7fecdc6de268>]"""

squares2 = []
for m in multipliers():
    squares2.append(m(2))
print(squares2)
[6, 6, 6, 6]

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/42558.html

相關(guān)文章

  • python面試題之該死for循環(huán)系列”(一)

    摘要:這是一道魔性面試題,難倒了無數(shù)英雄好漢上面代碼的執(zhí)行順序是這樣的從上到下第一個函數(shù)就是實現(xiàn)了一個簡單的加法運算第二個函數(shù)是一個生成器函數(shù),如果調(diào)用它會返回一個生成器這一行調(diào)用了生成器函數(shù),所以此刻就是一個生成器它的本質(zhì)還是迭代器然后執(zhí)行循環(huán) 這是一道魔性面試題,難倒了無數(shù)英雄好漢…… def add(n,i): return n+i def test(): for i...

    wudengzan 評論0 收藏0
  • 數(shù)據(jù)分析面試題之Pandas中groupby

    摘要:昨天晚上,筆者有幸參加了一場面試,有一個環(huán)節(jié)就是現(xiàn)場編程題目如下示例數(shù)據(jù)如下,求每名學(xué)生對應(yīng)的成績最高的那門科目與,用實現(xiàn)這個題目看上去很簡單,其實,并不簡單。 ??昨天晚上,筆者有幸參加了一場面試,有一個環(huán)節(jié)就是現(xiàn)場編程!題目如下:??示例數(shù)據(jù)如下,求每名學(xué)生(ID)對應(yīng)的成績(score)最高的那門科目(class)與ID,用Python實現(xiàn): showImg(https://se...

    ThinkSNS 評論0 收藏0
  • 用9種辦法解決 JS 閉包經(jīng)典面試題之 for 循環(huán)取 i

    摘要:閉包正確的說應(yīng)該是指一個閉包域每當(dāng)聲明了一個函數(shù)它就產(chǎn)生了一個閉包域可以解釋為每個函數(shù)都有自己的函數(shù)棧每個閉包域?qū)ο蠖加幸粋€不是屬性內(nèi)默認(rèn)有個名為的全局引用有了這個引用就可以直接調(diào)用的屬性或方法凡是在閉包域內(nèi)聲明的變量或方法外部無法直接訪問 閉包 正確的說,應(yīng)該是指一個閉包域,每當(dāng)聲明了一個函數(shù),它就產(chǎn)生了一個閉包域(可以解釋為每個函數(shù)都有自己的函數(shù)棧),每個閉包域(Function...

    Betta 評論0 收藏0
  • JS面試題之比較兩個對象是否相等?

    摘要:這是我在一次面試中,被面試官所提問的一道題在這次面試題中相等指的是對象的屬性個數(shù)值相等有這樣兩個李德華張德華我能想到的一種方案解答過程的思考由于沒有,我只能通過轉(zhuǎn)化成數(shù)組進(jìn)入第二步,對象中的屬性在另一個中是否存在。 這是我在一次面試中,被面試官所提問的一道題 在這次面試題中 相等:指的是對象的屬性個數(shù)值相等 有這樣兩個obj let obj1 = { name:李德華, ...

    wangbjun 評論0 收藏0
  • 你不能錯過前端面試題合集

    摘要:收集的一些前端面試題從面試題發(fā)現(xiàn)不足,進(jìn)而查漏補缺,比通過面試更難得及各大互聯(lián)網(wǎng)公司前端筆試面試題篇及各大互聯(lián)網(wǎng)公司前端筆試面試題篇面試題個和個經(jīng)典面試題前端開發(fā)面試題如何面試前端工程師很重要個變態(tài)題解析如何通過餓了么面試輕 收集的一些前端面試題 從面試題發(fā)現(xiàn)不足,進(jìn)而查漏補缺,比通過面試更難得 1 BAT及各大互聯(lián)網(wǎng)公司2014前端筆試面試題--Html,Css篇 2 BAT...

    ninefive 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<