Вы можете использовать строку как итеративную непосредственно:
def characters(string, sentinel):
for c in string:
if c == sentinel:
break
yield c
>>> list(characters('abczdef', 'z'))
['a', 'b', 'c']
Более функциональный подход, как вы и предполагали, будет:
from itertools import takewhile
def characters(string, sentinel):
return takewhile(lambda c: c != sentinel, string))
Использованиеiter(callable, sentinel)
Форма также может работать, но я считаю, что другие решения более читабельны:
def characters(string, sentinel):
chars = iter(string)
return iter(lambda: next(chars), sentinel)
Почему ваша попытка "зависает" на компьютере
list(iter(myfunc,'z'))
эквивалентно:
result = []
while True:
x = myfunc()
if x == 'z':
break
result.append(x)
Если вы посмотрите на то, что происходит при вызове myfunc()
:
>>> myfunc()
<generator object myfunc at 0x7f1e0f1020a0>
>>> myfunc()
<generator object myfunc at 0x7f1e0f1020f8>
>>> myfunc()
<generator object myfunc at 0x7f1e0f1020a0>
, вы увидите, что он каждый раз создает новый объект-генераторэто называется.
Очевидно, что ни один из этих объектов не равен 'z'
, поэтому это создает бесконечный цикл.