2017-01-29 57 views
3

生成生成聚合結果的生成器的Pythonic方法是什麼?在元的代碼,這樣的事情(而不是真實的,因爲我的Python版本不支持混合的產量和返回):生成生成器和聚合結果的Python函數

def produce(): 
    total = 0 
    for item in find_all(): 
     total += 1 
     yield item 

    return total 

在我看來,我可以:

  1. 不作produce()一個發電機,但傳遞一個回調函數來調用每個item
  2. 對於每個yield,還有yield到目前爲止的總計結果。我寧願不計算每個產量的中間結果,只有在完成時。
  3. 發送一個dict作爲produce()的參數,該參數將填充聚合結果。
  4. 使用全局來存儲聚合結果。

所有這些似乎沒有太大的吸引力...

NB。 total是一個簡單的例子,我的實際代碼需要複雜的聚合。我需要produce()完成之前的中間結果,因此是一個發電機。

+1

所以總同樣是迭代的長度的僅僅是等效由'find_all'返回?爲此你可以使用'enumerate'。 –

回答

3

也許你不應該使用一個生成器,而是一個迭代器。

def findall(): # no idea what your "find_all" does so I use this instead. :-) 
    yield 1 
    yield 2 
    yield 3 

class Produce(object): 
    def __init__(self, iterable): 
     self._it = iterable 
     self.total = 0 

    def __iter__(self): 
     return self 

    def __next__(self): 
     self.total += 1 
     return next(self._it) 

    next = __next__ # only necessary for python2 compatibility 

也許更清楚地看這一個例子:

>>> it = Produce(findall()) 
>>> it.total 
0 
>>> next(it) 
1 
>>> next(it) 
2 
>>> it.total 
2 
0

我錯過了什麼嗎?爲什麼不:

def produce(): 
    total = 0 
    for item in find_all(): 
     total += 1 
     yield item 

    yield total 
+0

謝謝,我沒有想到這個!它可以工作,但調用者必須弄清楚它是否有'item'對象或'total'對象。嗯。 – Willem

1

可以使用enumerate來算的東西,例如

i=0 
for i,v in enumerate(range(10), 1): 
    print(v) 
print("total",i) 

(注意枚舉的初始值)

對於更復雜的東西,你可以使用相同的原理,製作一個generato r產生兩個值並在迭代中忽略一個值,並在完成後使用它。

其它替代方案是在任一情況下經過一個可修改的對象,例如

def produce(mem): 
    t=0 
    for x in range(10): 
     t+=1 
     yield x 
    mem.append(t) 

aggregate=[] 
for x in produce(aggregate): 
    print(x) 
print("total",aggregate[0]) 

結果對於該實施例中

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
total 10