2017-10-08 72 views
1

我有以下的代碼:與嵌套列表理解奇怪行爲

[e for e in [sl] for sl in [1,[2,3],4,5]] 

我認爲是等效(在輸出方面)到:

[sl for sl in [1,[2,3],4,5]] 

然而,儘管後者產生:[1,[2,3],4,5]前者的回報:[5, 5, 5, 5]


我認爲,必須對嵌套for-statements進行了評估。

我在這裏發現了一個類似的案例Weird behavior: Lambda inside list comprehension但由於它使用了匿名函數,所以這種行爲背後的原因應該是不同的。

顯然,有些東西我錯過了,我看不到。

謝謝你的任何澄清

UPDATE

帕特里克指出,兩個for的順序是錯誤的,除非sl被定義之前不應該運行。我騙自己這裏,因爲我跑的例子在解釋和[sl for sl in [1,[2,3],4,5]]被執行第一離開sl組到列表中的最後一個值globals()


現在將是巨大的,明白這是怎麼評價

[e for e in [sl] for sl in [1,[2,3],4,5]] 

以產生[5, 5, 5, 5]輸出。

回答

2

sl在代碼的其他地方定義的嗎?也許作爲5?正如所寫的,你的第一個例子不應該運行,並且不會在Python 3.6中爲我運行。正確的方式來寫這將是這裏sl在使用前被定義

[e for sl in [1,[2,3],4,5] for e in [sl]] 

注意。

編輯:

Python從左到右讀取列表解析。當它到達for e in [sl]時,它會基於它已知的內容評估表達式[sl],而不讀取該行的其餘部分。你列出的理解是那麼像

[e for e in [5] for sl in [1,[2,3],4,5]] 

由於有四個sl[[1,[2,3],4,5]],您在結果列表獲得5四倍。

當寫列表內涵,是很自然的他們從小寫到大

e for e in x for x in y for y in z #wrong 

但你應該真正把它們寫從右到左,這樣解釋識別您在嵌套內涵使用標識符

e for y in z for x in y for e in x 

這無異於普通的循環for不同:

for e in x: 
    for x in y: 
     for y in z: 
      print(e) 

很明顯是錯誤的,列表解析也沒有什麼不同。

+0

哦,不,它只是行實際上和我運行實例在翻譯。但是,是的,你確實是對的!我必須在[1,[2,3],4,5]]'之前運行'sl [sl,],因此'sl'保持設置爲'globals()'中列表的最後一個值。這也解釋了爲什麼倒置的「for」工作。然而,在全局變量中把'sl'設置爲'5',你會如何解釋[1,[2,3],4,5]]中'[e for [in sl] for sl的行爲? –

+0

我的意思是,我理解最左邊的'for'local'sl'會正確地覆蓋全局變量。我只是想了解當sl'已經設置時我的解決方案是如何評估的 –

+0

@holak請參閱我的編輯(它很大以適合評論)。如果這仍然沒有幫助,請隨時多問。 –

0

代碼可以運行的唯一方法是在其他地方定義了sl。如果是(如5),則代碼:

sl = 5 

[e for e in [sl] for sl in [1,[2,3],4,5]] 

產生的輸出:

[5,5,5,5] 

爲什麼呢?

發生這種情況的原因是for-loopsevaluateleftright。所以,第一件事情是發生的e被分配到5 - 就像你可以正確的:

[i for i in [9]] 

這將使9

所以,現在我們知道,無論是最右邊的for-loop的,的e值將始終是中sl所以在我們的例子5。現在,爲什麼輸出[5,5,5,5]?那麼它的混亂,因爲變量sl正在重新使用。但是,這不會影響list-comprehensionleft,因爲它將left評估爲right。因此無論sl位於右側,e的值始終爲[sl]5)。右手loop只是作爲一個計數器。由於其中有4個元素(1,[2,3],4,5),所以左邊部分運行4次。但e始終是5所以每個時間e被調用,它是5 - 產生結果[5,5,5,5]

爲了證明右手邊是一個簡單的計數器,下面將所有產生[5,5,5,5]相同的結果:

[e for e in [sl] for _ in [1, [2,3], 4, 5]] 
[e for e in [sl] for sl in [0, 0, 0, 0]] 
[e for e in [sl] for _ in range(4)] 
[e for e in [sl] for sl in range(4)]