检查发电机是否真的在一条线上产生了一些东西

时间:2012-03-15 08:35:39

标签: python iterator generator

当结果是某些集合时,我使用的许多函数返回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!'

我想知道是否有更简洁的方法来解决这个问题在一行

4 个答案:

答案 0 :(得分:4)

这是使用itertools tee函数的一种方法,它复制了生成器:

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 :(得分:3)

zip个东西吃了第一个产品,所以这也不是一个好主意。

您只能通过获取并保持生成器来检测生成器是否有产品,直到需要为止。以下课程将帮助您完成此任务。

如果需要,它会从迭代器中获取一个项目并保留它。

如果要求清空(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()方法也完全有效......

答案 2 :(得分: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

答案 3 :(得分: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)