[英]recursion to reset a generator in python
我正在尝试编写一个函数,该函数返回生成器的下一个元素,如果它在生成器的末尾,它将对其进行重置并返回下一个结果。 以下代码的预期输出为:
1
2
3
1
2
但是,这显然不是我得到的。 我在做什么,那是不正确的?
a = '123'
def convert_to_generator(iterable):
return (x for x in iterable)
ag = convert_to_generator(a)
def get_next_item(gen, original):
try:
return next(gen)
except StopIteration:
gen = convert_to_generator(original)
get_next_item(gen, original)
for n in range(5):
print(get_next_item(ag,a))
1
2
3
None
None
您需要返回递归调用的结果:
return get_next_item(gen, original)
仍然没有使它可行。 for循环中使用的生成器ag
不会因函数中局部变量gen
的重新绑定而改变。 它将筋疲力尽...
正如评论中提到的,请查看itertools.cycle
。
get_next_item
是一个生成器,它返回一个迭代器,该迭代器通过__next__
方法为您提供它yield
的值。 因此,您的陈述没有任何作用。
您要做的是:
def get_next_item(gen, original):
try:
return next(gen)
except StopIteration:
gen = convert_to_generator(original)
for i in get_next_item(gen, original):
return i
或更短,并且完全等效(只要gen
可能具有__iter__
方法):
def get_next_item(gen, original):
for i in gen:
yield i
for i in get_next_item(convert_to_generator(original)):
yield i
或不进行递归(这在python中是一个大问题,因为它的限制是1.深度有限且2.缓慢):
def get_next_item(gen, original):
for i in gen:
yield i
while True:
for i in convert_to_generator(original):
yield i
如果convert_to_generator只是对iter
的调用,它会更短:
def get_next_item(gen, original):
for i in gen:
yield i
while True:
for i in original:
yield i
或者,使用itertools
:
import itertools
def get_next_item(gen, original):
return itertools.chain(gen, itertools.cycle(original))
如果保证gen
可以作为original
的迭代器,则get_next_item
等同于itertools.cycle。
旁注:您可以for i in x: yield i
交换for i in x: yield i
表示使用Python 3.3或更高版本yield from x
(其中x
是某些表达式) yield from x
。
itertools.cycle(iterable)是否可能替代?
最简单的方法是使用itertools.cycle ,否则,如果说iterable是一个迭代器(又称生成器),则需要记住iterable中的元素,以防无法重置,如果它不是迭代器,则可以重用它多次。
该文档包括一个示例实现
def cycle(iterable):
# cycle('ABCD') --> A B C D A B C D A B C D ...
saved = []
for element in iterable:
yield element
saved.append(element)
while saved:
for element in saved:
yield element
或者例如做重复使用的事情
def cycle(iterable):
# cycle('ABCD') --> A B C D A B C D A B C D ...
if iter(iterable) is iter(iterable): # is a iterator
saved = []
for element in iterable:
yield element
saved.append(element)
else:
saved = iterable
while saved:
for element in saved:
yield element
示例使用
test = cycle("123")
for i in range(5):
print(next(test))
现在关于您的代码,问题很简单,它不记得它的状态
def get_next_item(gen, original):
try:
return next(gen)
except StopIteration:
gen = convert_to_generator(original) # <-- the problem is here
get_next_item(gen, original) #and you should return something here
在标记的行中,构建了一个新的生成器,但是您需要在此函数之外更新ag
变量以获得所需的行为,有多种方法可以完成此操作,例如更改函数以返回元素和生成器,还有其他方法方式,但不建议使用它们,或更不建议像构建类那样复杂,这样它就可以记住其状态
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.