2012-03-15 72 views
2

許多圖書館的功能我用回generator!而非list■當結果是一些收藏。檢查發電機真的在一行中產生的東西

有時候,我只是想檢查如果結果是空的沒有了,當然我不會寫這樣的:

result = return_generator() 
    if result: 
     print 'Yes, the generator did generate something!' 

現在我來了一行代碼是沒有解決這個問題消費發生器:

result = return_generator() 
    if zip("_", result): 
     print 'Yes, the generator did generate something!' 

我不知道是否有簡潔的方式來解決這個問題在一行

+0

*嘆*我今天有一個真正的大腦褪色。我急切地等待有人回答這個問題。 :P – detly 2012-03-15 08:47:42

+0

@detly不,它不消耗發電機。您可以編寫一個生成器,在生成和測試時進行打印。 – satoru 2012-03-15 08:48:49

+0

是的,我意識到,當我測試它(雖然它消耗的第一個項目)。這就是爲什麼我刪除了我原來的評論:P – detly 2012-03-15 08:58:01

回答

3

zip東西吃的第一個項目產生,所以它不是一個好主意爲好。

如果發生器由獲得並保持它,直到得到所需的項目只能檢測。以下課程將幫助你這樣做。

如果需要,它會從迭代器中獲取一個項目並保留它。

如果要求emptyness(if myiterwatch: ...),它會嘗試獲取並返回如果能得到一個。

如果問下一個項目,它將返回檢索到的一個或一個新的。

class IterWatch(object): 
    def __init__(self, it): 
     self.iter = iter(it) 
     self._pending = [] 
    @property 
    def pending(self): 
     try: 
      if not self._pending: 
       # will raise StopIteration if exhausted 
       self._pending.append(next(self.iter)) 
     except StopIteration: 
      pass # swallow this 
     return self._pending 
    def next(self): 
     try: 
      return self.pending.pop(0) 
     except IndexError: 
      raise StopIteration 
    __next__ = next # for Py3 
    def __iter__(self): return self 
    def __nonzero__(self): 
     # returns True if we have data. 
     return not not self.pending 
     # or maybe bool(self.pending) 
    __bool__ = __nonzero__ # for Py3 

這解決了一個非常通用的方式的問題。如果你有,你只是想測試一個迭代器,你可以使用

guard = object() 
result = return_generator() 
if next(result, guard) is not guard: 
    print 'Yes, the generator did generate something!' 

next(a, b)回報b如果迭代器a耗盡。所以如果它在我們的情況下返回警衛,那麼它不會產生任何東西,否則它會發生。

但你zip()的做法是完全合法的,以及...

+0

是的,考慮到我想稍後使用發生器的條件,我必須做一些事情來恢復消耗的「第一元素」。但是我認爲這是非常罕見的,因爲在這種情況下,我只是在事先沒有檢查的情況下迭代生成器。 – satoru 2012-03-15 08:59:37

+0

謝謝你解釋'next'的第二個參數:) – satoru 2012-03-15 09:07:27

2

而不是返回發電機,只是使用它?以下是可能返回結果或不返回結果的生成器示例 - 如果有結果採取行動,如果沒有結果,則不採取任何行動。

#!/usr/bin/python 

import time 

def do_work(): 
    if int(time.time()) % 2: 
     for a in xrange(0,100): 
      yield a 

for thing in do_work(): 
    print thing 
+0

通常情況下,這可能會起作用,但可能會出現這種情況,無法正常工作。 – glglgl 2012-03-15 08:54:34

+1

那麼,我在我的座位邊緣..什麼類型的情況? – synthesizerpatel 2012-03-15 09:00:37

+0

@glglgl:如? (可能值得在現有答案中詳細說明。) – 2012-03-15 09:01:30

4

這裏使用itertools單向三通功能,複製發電機:

from itertools import tee 
a, b = tee(xrange(0)) 
try: 
    next(a) 
    print list(b) 
except StopIteration: 
    print "f1 was empty" 


a, b = tee(xrange(3)) 
try: 
    next(a) 
    print list(b) 
except StopIteration: 
    print "f2 was empty" 

>>> 
[0, 1, 2, 3] 
f2 was empty 
+1

+1教給我一些東西。有什麼'itertools'不能做? – 2012-03-15 09:28:18

+1

謝謝。只是要小心,如果iterables的一個(A或B)得到遠遠領先於其他迭代器,它的所有生成的值必須存儲在列表中的其他迭代以後得到的。所以這個解決方案可能會使用大量內存。我提出了一個更好的解決方案。 – 2012-03-15 09:30:54

+0

'DEF F(N):返回(在範圍I爲I(N))','三通(F(10))','三通(F(0))'將是一個替代 – glglgl 2012-03-15 10:45:53

1

這裏有適合自己情況的兩個最簡單的解決方案我可以想到:

def f1(): 
    return (i for i in range(10)) 

def f2(): 
    return (i for i in range(0)) 


def has_next(g): 
    try: 
     from itertools import chain 
     return chain([g.next()],g) 
    except StopIteration: 
     return False 

g = has_next(f1()) 
if g: 
    print list(g) 

g = has_next(f2()) 
if g: 
    print list(g) 


def has_next(g): 
    for i in g: 
     return chain([i],g) 
    return False 

g = has_next(f1()) 
if g: 
    print list(g) 

g = has_next(f2()) 
if g: 
    print list(g) 
+0

的'對i在克:返回鏈([我],克)'花了我一段時間才明白。但它很好:-) – glglgl 2012-03-15 10:45:07