我有一个生成器函数A
。
例如(实际上我有一个更复杂的功能A
)
def A():
yield from [i**2 for i in range(20)]
编写另一个生成器函数B
,我想枚举A
返回的所有元素,除了第一个元素。
在Python 3中实现此功能的简洁方法是什么?
答案 0 :(得分:7)
itertools.islice(generator,1,None)
答案 1 :(得分:3)
通常,您不需要在表达式中使用它,因此只需调用next(it)
,而忽略结果即可消耗和丢弃第一个元素。
但是,如果迭代器可能为空,则必须决定要发生的事情:
StopIteration
,在这种情况下,next(it)
很好。next(it)
在except StopIteration: raise SomethingElse()
内。next(it, None)
。 您可以在stdlib和docs中找到这些示例。例如,如果您浏览itertools
中的食谱:
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
这正是您想要做的—跳过b
的第一个元素。而且,如果iterable
为空,则您不想在这里出现错误;您只想不进行任何迭代。因此,next(b, None)
。
如果需要在表达式中间执行此操作怎么办?
然后,您可以编写一个跳过第一个元素的函数:
def skip_first(iterable):
it = iter(iterable)
next(it, None)
return it
(同样,对于空的可迭代对象,您必须决定要发生什么。)
这将返回迭代器的第一个跳过版本,因此您可以内联使用它。 (当然,它还会突变您传入的迭代器,但是通常只使用不保留任何引用的临时值,所以这不是问题。)
或者,如果您需要返回一个生成器而不是一个任意的迭代器(通常不需要):
def skip_first(iterable):
it = iter(iterable)
next(it, None)
yield from it
或者您可以使用同一想法的更通用版本itertools.islice
。以下具有相同的效果:
it = skip_first(it)
it = itertools.islice(it, 1, None)
虽然我们使用itertools
食谱,但值得一看的是consume
:
def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is None, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
忘记None
部分;有趣的是,它跳过了n
和islice
的{{1}}元素。 (请注意,它是在原位更改next
,而不返回任何内容。)
答案 2 :(得分:1)
免责声明:请参阅上面的@abarnert和@Solaxun的答案。
只是认为应该提到以下内容
如果有original = iter((1,2,3,4,5))
然后
first, remaining = next(original), original
其中remaining
是没有第一个元素的迭代器。