Функция перестаёт работать корректно внутри другой функции
Есть задача, где необходимо написать бесконечный итератор по строке, т.е. нужно, чтобы после того, как элементы закончатся, выводились заново все элементы строки.
Я написал вот такое, и это, кажется, работает:
def do_stuff(s):
i = 0
while len(s) > 0:
try:
yield s[i]
i += 1
except IndexError:
i = 0
foo = do_stuff('word')
Но проблема в том, что по условию задачи вывод должен осуществляться не через next(foo), а просто через foo().
Тогда я попытался сделать следующим образом:
def make_looper(s):
def do_stuff():
i = 0
while len(s) > 0:
try:
yield s[i]
i += 1
except IndexError:
i = 0
return next(do_stuff())
foo = make_looper('word')
Но теперь возникает две проблемы:
print(foo())выдаёт, что объект неcallable. Что в принципе понятно, потому чтоnext(do_stuff())- строка.print(foo)всё время выводит на печать только первый элемент строки.
Подскажите, пожалуйста, как можно это исправить?
Ответы (1 шт):
def make_looper(s):
iterable = iter(s)
def looper():
nonlocal iterable
# nonlocal нужно чтобы можно было перезаписать переменную iterable во внешней функции
try:
return next(iterable)
except StopIteration:
iterable = iter(s)
return next(iterable)
return looper
foo = make_looper('word')
print(foo())
print(foo())
print(foo())
print(foo())
print(foo())
print(foo())
print(foo())
print(foo())
print(foo())
Вывод:
w
o
r
d
w
o
r
d
w
Другой вариант:
def make_looper(s):
i = -1
def do_stuff():
nonlocal i
i += 1
if i >= len(s):
i = 0
return s[i]
return do_stuff
"Про"-версия с использованием функции cycle из itertools, которая возвращает итератор, который бесконечно повторяет элементы исходной последовательности (по сути делает то что у вас делала первоначальная версия функции do_staff):
from itertools import cycle
def make_looper(s):
iterable = cycle(s)
def looper():
return next(iterable)
return looper