Этот 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()
подход также вполне допустим ...