2013-04-03 26 views
5

我試圖對同一套裝(卡片)的卡片進行分組,並將其排列在生成器中,並將這些生成器存儲在列表理解中。在列表理解中創建多個生成器

我想出的解決方案除了所有的發電機包含完全相同的卡的事實。任何想法爲什麼?

這裏是在此基礎上的代碼

deck=range(52) 

gens=[(i for i in deck if i%13==v) for v in range(13)] 

我預計例如:

gens[1].next() 
1 
gens[1].next() 
14 


gens[10].next() 
10 
gens[10].next() 
23 

而是我得到

gens[1].next() 
12 

gens[1].next() 
25 

gens[1].next() 
38 

並返回列表中的所有發電機相同的結果..

回答

7

問題在於您的生成器表達式中的名稱v在列表理解中引用該變量v。因此,當您的生成器表達式實際運行的代碼(當您調用next時)時,它會查看變量v並看到值12,無論創建生成器時v的值是多少。

一個解決辦法:

deck = range(52) 

def select_kth(v): 
    return (i for i in deck if i % 13 == v) 

gens = [select_kth(v) for v in range(13)] 

因爲我們定義的函數,名字v得到生活在它自己的命名環境等保持周圍不變。

如果你真的願意,你可以在一行做到這一點:

gens = [(lambda v: (i for i in deck if i % 13 == v))(v) for v in range(13)] 
+0

謝謝。這個答案和@abarnert都很好 – jule64 2013-04-03 19:35:26

5

如果你把它變成相當於嵌套循環,可以看到更容易範圍界定問題:

gens = [] 
for v in range(13): 
    def gen(): 
     for i in deck: 
      if i%13 == v: 
       yield i 
    gens.append(gen()) 

你最終有13個發電機都綁定到相同的值v,12。

因此,這裏的解決方案與其他任何範圍問題相同:您需要創建一個新的範圍,其中v。最簡單的方法是創建一個新功能:

gens = [(lambda x: (i for i in deck if i%13==x)(v) for v in range(13)] 
+0

我打算刪除這個,因爲它的確和杜加爾的答案一樣,他在我面前一分鐘就到了,但是......它有一些upvotes,所以我猜人們認爲這是值得的不管怎麼說...或者也許Dougal應該只是將轉換複製到嵌套循環中,並且在一個答案中擁有兩全其美的優點? – abarnert 2013-04-03 19:15:26

+0

你的回答是完全不同的解釋方式。我會離開它。 – William 2013-04-03 19:23:45

+0

我喜歡你的解釋,認爲值得自己保留,而不是偷取它,不需要刪除。 :) – Dougal 2013-04-03 20:30:07

相關問題