python生成器是列表的良好替代品,在大多数情况下,我希望检查空条件,这是普通生成器无法实现的。我正在尝试编写一个包装器,它将允许检查空状态,但仍然是懒惰的并且提供了生成器的好处。
class mygen:
def __init__(self,iterable):
self.iterable = (x for x in iterable)
self.peeked = False
self.peek = None
def __iter__(self):
if self.peeked:
yield self.peek
self.peeked = False
for val in self.iterable:
if self.peeked:
yield self.peek
self.peeked = False
yield val
if self.peeked:
yield self.peek
self.peeked = False
def __nonzero__(self):
if self.peeked:
return True
try:
self.peek = self.iterable.next()
self.peeked = True
return True
except:
return False
- 我认为它的行为像普通的发电机一样。是否有任何角落案例
我丢了?
- 这看起来并不优雅。是否有更好的更多pythonic方式做同样的事情?
样品用法:
def get_odd(l):
return mygen(x for x in l if x%2)
def print_odd(odd_nums):
if odd_nums:
print "odd numbers found",list(odd_nums)
else:
print "No odd numbers found"
print_odd(get_odd([2,4,6,8]))
print_odd(get_odd([2,4,6,8,7]))
我通常不会实现这种方式
发电机。如何测试迭代器有一种惯用的方法 it
筋疲力尽:
try:
next_item = next(it)
except StopIteration:
# exhausted, handle this case
用一些项目特定的LBYL习语代替这个EAFP成语似乎
令人困惑,根本没有益处。
也就是说,如果我真的想要,我将如何实现这一点:
class MyIterator(object):
def __init__(self, iterable):
self._iterable = iter(iterable)
self._exhausted = False
self._cache_next_item()
def _cache_next_item(self):
try:
self._next_item = next(self._iterable)
except StopIteration:
self._exhausted = True
def __iter__(self):
return self
def next(self):
if self._exhausted:
raise StopIteration
next_item = self._next_item
self._cache_next_item()
return next_item
def __nonzero__(self):
return not self._exhausted
使用 itertools.tee
实现非零测试,并简单地将其缓存在创建上:
from itertools import tee
class NonZeroIterable(object):
def __init__(self, iterable):
self.__iterable, test = tee(iter(iterable))
try:
test.next()
self.__nonzero = True
except StopIteration:
self.__nonzero = False
def __nonzero__(self):
return self.__nonzero
def __iter__(self):
return self.__iterable
小演示:
>>> nz = NonZeroIterable('foobar')
>>> if nz: print list(nz)
...
['f', 'o', 'o', 'b', 'a', 'r']
>>> nz2 = NonZeroIterable([])
>>> if not nz2: print 'empty'
...
empty
这个版本的NonZeroIterable缓存了标志;因此 只要 告诉你迭代器在开始时是否为非空。如果您需要能够在其生命周期的其他点测试迭代,请使用 斯文的版本 代替;那里 __nonzero__
国旗会告诉你 每次迭代后 如果有更多的物品要来。
关于你的例子的旁注
您的示例代码太简单了,对您的用例来说不是一个好的参数;首先测试非空(可能在输入列表上迭代以查找奇数),但无论如何都要耗尽整个迭代器。以下代码同样有效,并且不需要您发明破解python习语的方法:
def print_odd(odd_nums):
odd_nums = list(odd_nums)
if odd_nums:
print "odd numbers found", odd_nums
else:
print "No odd numbers found"