python面試題之「該死的for循環系列」(一)

這是一道魔性面試題,難倒了無數英雄好漢……

def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()
for n in [1,10]:
    g=(add(n,i) for i in g)
print(n)
print(list(g))
10
[20, 21, 22, 23]

上面代碼的執行順序是這樣的:從上到下:

第一個函數add就是實現了一個簡單的加法運算
第二個函數test是一個生成器函數,若是調用它會返回一個生成器
g=test(),這一行調用了生成器函數,因此此刻g就是一個生成器(它的本質仍是迭代器)
而後執行for循環,這裏迷惑人的就是這個for循環,爲了減小它的魔性,咱們把for循環拆開來看:
    當n = 1時:
    執行了:g=(add(n,i) for i in g)
    當n = 10時:
    執行了:g=(add(n,i) for i in g)

乍一看這兩行代碼仍是有點迷糊,可是咱們要知道,生成器有個最大的特性就是惰性,當你不進行迭代時它就不進行運算,想要對生成器進行迭代有如下幾種方法:
第一種:for循環,for循環的本質就是調用了iter和next方法進行了迭代
第二種:調用next方法
第三種:調用send方法
第四種:數據類型強制轉換,好比使用list()強制轉換。
只要沒有以上四種方法進行迭代,那麼生成器就沒有進行運算,因此在上面的for循環中不管是n=1時仍是n=10時,生成器 g 都沒有參與運算,python

當n = 1時,g=(add(n,i) for i in g),這個表達式的結果g 就是一個表達式,沒有進行運算,g的值就是一個表達式(add(n,i) for i in g),括號裏面的g其實是test(),因此g = (add(n,i) for i in test()),僅此而已
當n = 10時,g=(add(n,i) for i in g),把n=1時的g的結果帶入進去就是g=(add(n,i) for i in (add(n,i) for i in test()))面試

當整段代碼執行到print(list(g))語句以前,g的值就是一段代碼,或者你能夠稱之爲算法,沒有進行任何運算,裏面的n就是n,g就是g
不過此時由於代碼是按照流程執行的,而且for循環已經執行完畢,因此n的值等於10算法

當執行print(list(g))語句時,生成器纔開始輸出數據,此時執行最後一個g的賦值語句:
g=(add(n,i) for i in (add(n,i) for i in test()))
這時 n 的值等於10(由於代碼是按照流程執行的,for循環已經執行完了,n的最終結果就是10),其中後面的(add(n,i) for i in test())這段代碼的結果依然是個生成器,迭代後應爲[10,11,12,13],因此最終的結果能夠理解成:(add(n,i) for i in [10,11,12,13]),因此最終結果爲:20,21,22,23函數

相關文章
相關標籤/搜索