[英]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.