2011-11-16 46 views
1

我想在我的發電機的以下兩個定義之間做出決定。哪個更好?這是「更pythonic」?無論如何要緩解每個人的缺點?Python生成器 - 突變最後結果?

def myGenerator1(howMany): 
    result = [0,0,0] 
    yield result 
    for i in range(howMany) 
     modifyListInPlace(result) 
     yield result 

for val in myGenerator1(1000): 
    useValThenForgetIt(val) 

def myGenerator2(howMany): 
    result = (0,0,0) 
    yield result 
    for i in range(howMany) 
     result = createNewUpdatedTuple(result) 
     yield result 

for val in myGenerator2(1000): 
    useValThenForgetIt(val) 

第一個修改已經由發電機回來,可能與調用,我還沒有預見到的代碼搞亂的值。第二種情況下,在這種情況下產生1000元的垃圾,或者如果我增加「howMany」(我可能會)。

我給出的循環只是我當前使用的生成器。我不想認爲我會永遠保存它的值,但它是一個有用的工具,可能在別處有用。

+0

如果你擔心「垃圾」對性能的影響,那麼**測試性能**。 –

+0

好點。我並不是特別關注表現,而是更多地尋找關於這種設計是好的做法還是令人不悅的指導。 –

+0

@雷蒙德非常感謝我的建設性答案,即使我意識到這是一個愚蠢的問題。我是一個Python小菜鳥,所以仍然在思考我的方式。我跟隨了itertools的鏈接,結果發現我正在尋找itertools.product([[0,1,2]] * 3),但知道它返回了一堆不同的元組。 –

回答

3

以標準庫爲參考,itertools模塊中的組合函數都返回了元組,雖然底層算法是mutate-in-place算法。例如,查看itertools.permutations的代碼。

這種設計(返回元組而不是列表)已被證明是可靠的。我擔心變異列表方法會根據調用者對迭代器的返回值做些什麼來創建一些難以發現的錯誤。

另一個想法。對於未使用的結果,我不會過分擔心「爲數千個元組創建垃圾」。 Python的元組實現非常適合重複使用先前處理過的元組(通過使用一個freelist數組,它可以在不調用內存分配器的情況下從之前使用的元組創建一個新元組)。所以,元組版本只是列表版本的性能,或者更好一點。

+0

非常感謝我的建設性答案,甚至我意識到這是一個愚蠢的問題。我是一個Python小菜鳥,所以仍然在思考我的方式。我跟隨了itertools的鏈接,結果發現我正在尋找itertools.product([[0,1,2]] * 3),但知道它返回了一堆不同的元組。 –

1

事實上,第一個可以返回一個對象,然後在返回後顯然修改它,這對我來說是一個巨大的代碼味道,無論你使用什麼語言(即它不是一個「 Python化「)。另外,爲什麼你會想要一個函數產生一個迭代器重複相同的值,在產量之間進行修改?對我來說似乎很不直觀。

如果使用這些值,則由myGenerator2創建的元組不是垃圾。如果你一次使用它們,它們將永遠不會同時存在,並且你的程序幾乎肯定會做很多其他的內存分配/釋放。與由range(howMany)返回的列表不同,創建1000個實際上不會使用的整數(除非您使用Python3,range返回一個生成器而不是列表)。

如果有任何機會都呼叫者可能要掛到由您的發電機返回類似的參考(和Python程序員普遍預期,給發電機的時候,才能夠去items = list(generator)如果他們需要不止一次地使用它們),那麼第二個就要優越得多。

+0

爲什麼?計算base3,然後使用「digits」(trigits?)作爲索引到列表中,然後完成結果。原來我正在尋找itertools.product([[0,1,2]] * 3)。 –

+0

@Mike只是令人驚訝,而且令人驚訝導致錯誤。 Python程序員不希望迭代某些東西來產生副作用,除了消費輸入,如果它是一個生成器。它更緊密地將發生器的調用者與其實現聯繫起來;來電者必須意識到他們無法做任何他們想做的事情。在實際操作中發生的調試和*肯定*錯誤的程序員時間都比幾乎所有情況下的小性能損失都要昂貴。 – Ben