Python 检查发电机是否真的在一条线上产生了一些东西
当结果是某个集合时,库的许多函数我使用returnPython 检查发电机是否真的在一条线上产生了一些东西,python,iterator,generator,Python,Iterator,Generator,当结果是某个集合时,库的许多函数我使用returngenerators而不是lists 有时我只想检查结果是否为空,当然我不能写这样的东西: result = return_generator() if result: print 'Yes, the generator did generate something!' 现在,我提出了一种解决此问题而不消耗发电机的单衬套: result = return_generator() if zip("_", res
generator
s而不是list
s
有时我只想检查结果是否为空,当然我不能写这样的东西:
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!'
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
我想知道是否有更干净的方法来解决这个问题,只需一行?而不是返回发电机,直接使用它?下面是一个生成器示例,它可能返回结果,也可能不返回结果-如果有结果,则执行操作;如果没有结果,则不执行操作
#!/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
这个
zip
东西会吃掉第一件物品,所以这也不是一个好主意
您只能通过获取并保存到需要时,才能检测生成器是否有项目。下面的课程将帮助你做到这一点
如果需要,它从迭代器中获取一个项并保存它
如果请求清空(如果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)
如果迭代器a
耗尽,则返回b
。因此,在我们的例子中,如果它返回守卫,它不会生成任何东西,否则它会生成
但是您的
zip()
方法也是非常有效的…这里有一种方法使用itertools tee函数复制生成器:
result = return_generator()
if zip("_", result):
print 'Yes, the generator did generate something!'
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
以下是我能想到的两个最简单的解决方案:
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)
唉,我今天真是脑子不好。我急切地等待有能力回答这个问题的人P@detly不,它不会消耗发电机。你可以编写一个生成器,在生成和测试时打印。是的,我在测试它时意识到了这一点(尽管它消耗了第一项)。这就是为什么我删除了我最初的评论:正常情况下,这可能会起作用,但也有可能在某些情况下,这不起作用。好吧,我正处于我的座位边缘。。什么样的情况?@glglgl:比如说?(这可能值得在您现有的答案中详细说明。)考虑在使用生成的项目之前,您必须准备一些东西。这种准备可能很昂贵,如果没有要处理的项目,可以省略。可以将准备工作放入循环并设置标志(如果已完成),但将其置于循环之前看起来更好(IMHO)。是的,考虑到我以后要使用生成器的情况,我必须采取措施恢复消耗的“第一个元素”。但我认为这是非常罕见的,因为在这种情况下,我只需在生成器上迭代,甚至事先都没有检查。感谢您解释
next
:)+1的第二个参数,让我学到了一些东西。有什么是itertools不能做的吗?谢谢。只要小心,如果其中一个iterable(a或b)远远领先于另一个iterable,那么它生成的所有值都必须存储在一个列表中,以便另一个iterable稍后获得。因此,此解决方案可能会占用大量内存。我建议了一个更好的解决方案。def(n):return(在范围(n)内的I表示I))
,tee(f(10))
,tee(f(0))
将是另一种选择。for I in g:return chain([I],g)
我花了一段时间才理解。但这很好:-)