Модуль itertools
(на удивление) не предоставляет рецепт для следующей функции, которая обеспечивает повторяемость, состоящую из x
, g(x)
, g(g(x))
и т. Д .:
def iterate(g, x):
yield x
for y in iterate(g(x), g):
yield y
(Вышеприведенное предоставлено сторонним модулем toolz.itertoolz
. Его определение чище, чем у меня:
def iterate(g, x):
while True:
yield x
x = g(x)
)
Тогда ваша функция - это просто композиция iterate
и itertools.takewhile
:
def loopwhile(pred, g, f, *args, **kwargs):
for x in itertools.takewhile(pred, iterate(g, f(*args, **kwargs))):
yield x
Например,
>>> list(loopwhile(lambda x: x < 1024, lambda x: x * 2, lambda: 1))
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Вышеприведенные версии Python 3 немного проще:
def iterate(g, x):
yield x
yield from iterate(g, g(x))
def loopwhile(pred, g, f, *args, **kwargs):
yield from takewhile(pred, iterate(g, f(*args, **kwargs)))