在python中重置生成器的递归

在python中重置生成器的递归,python,recursion,generator,Python,Recursion,Generator,我试图编写一个函数,返回生成器的下一个元素,如果它在生成器的末尾,它将重置它并返回下一个结果。以下代码的预期输出为: 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:

我试图编写一个函数,返回生成器的下一个元素,如果它在生成器的末尾,它将重置它并返回下一个结果。以下代码的预期输出为:

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)
这仍然不能使这成为一种有效的方法。 重新绑定函数中的局部变量
gen
,不会改变for循环中使用的生成器
ag
。它会一直精疲力竭


正如评论中所提到的,请检查。

获取下一个\u项
是一个生成器,它返回一个迭代器,通过
\uuuuuu下一个\uu
方法为您提供它
生成的值。出于这个原因,你的声明没有任何作用

您要做的是:

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
\uuuuu iter\uuuu
方法,它可能有):

或者没有递归(这在python中是一个大问题,因为它1.深度有限,2.速度慢):

如果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
保证是
原始
的迭代器,则
get\u next\u项目
相当于itertools.cycle

旁注:您可以使用Python 3.3或更高版本将
交换为x中的i:yield i
交换为
yield from x
(其中
x
是一些表达式)。

是一种可能的替代方法吗?

简单的方法就是使用,否则,如果所述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
def get_next_项目(gen,原件):
尝试:
返回下一个(gen)
除停止迭代外:

gen=将_转换为_生成器(原始)#
将_转换为_生成器
做什么?请同时发布它的代码。您可能对它感兴趣,它还提供了一个示例实现。我添加了它@Jarvis@VincentSavard提供了答案。实际上我已经试过了。它只开始返回第一个元素
1,2,3,1,1
。如果
original
为空,则这将陷入一个无限的零循环sequence@Copperfield它应该做什么不同的事情?停止迭代?抛出异常?还是重复最后一个元素?我的代码片段与mnky9800n的代码完全相同。编辑:他想要他的代码做什么。简单,而不是
当为真时
do
当为原创时
所以如果
原创
为真时,它不会陷入无限的虚无循环empty@Copperfield这是一种选择,但我想抛出异常是更好的方法。问题是,它主要是基于意见的。我同意,目前的解决方案是最糟糕的,但它可以扩展以适合使用它的程序员的风格。
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