Python: итератор от функции
Что такое идиоматический способ создания бесконечного итератора из функции? Например
from itertools import islice
import random
rand_characters = to_iterator( random.randint(0,256) )
print ' '.join( islice( rand_characters, 100))
будет производить 100 случайных чисел
Ответы
Ответ 1
Вам нужен итератор, который постоянно дает значения, пока вы не перестанете просить его о новых? Просто используйте
it = iter(function, sentinel)
который вызывает function()
для каждого шага итерации до результата == sentinel
.
Поэтому выберите дозор, который никогда не может быть возвращен вашей желаемой функцией, например None
, в вашем случае.
rand_iter = lambda start, end: iter(random.randint(start, end), None)
rand_bytes = rand_iter(0, 256)
Если вы хотите отслеживать состояние на вашем компьютере, вы можете сделать
iter_mystate = iter(getstate, None)
который, в свою очередь, бесконечно называет getstate()
для каждого шага итерации.
Но будьте осторожны с функциями, возвращающими None
в качестве допустимого значения! В этом случае вы должны выбрать сторожевую систему, которая гарантированно будет уникальной, возможно, объект, созданный именно для этого задания:
iter_mystate = iter(getstate, object())
Ответ 2
Каждый раз, когда я вижу iter
с двумя аргументами, мне нужно почесать голову, чтобы посмотреть документацию, чтобы точно выяснить, что происходит. Просто из-за этого я бы, вероятно, бросил свой собственный:
def call_forever(callback):
while True:
yield callback()
Или, как указано в комментариях Джона Клемента, вы можете использовать рецепт itertools.repeatfunc
, который также позволяет передавать аргументы функции:
import itertools as it
def repeatfunc(func, times=None, *args):
"""
Repeat calls to func with specified arguments.
Example: repeatfunc(random.random)
"""
if times is None:
return it.starmap(func, it.repeat(args))
return it.starmap(func, it.repeat(args, times))
Хотя я считаю, что подпись функции def repeatfunc(func,times=None,*args)
немного неудобна. Я бы предпочел передать кортеж как args (мне кажется более явным, и "явный лучше, чем неявный" ):
import itertools as it
def repeatfunc(func, args=(),times=None):
"""
Repeat calls to func with specified arguments.
Example: repeatfunc(random.random)
"""
if times is None:
return it.starmap(func, it.repeat(args))
return it.starmap(func, it.repeat(args, times))
который позволяет называть его следующим:
repeatfunc(func,(arg1,arg2,...,argN),times=4) #repeat 4 times
repeatfunc(func,(arg1,arg2,...)) #repeat infinitely
вместо версии ванили от itertools
:
repeatfunc(func,4,arg1,arg2,...) #repeat 4 times
repeatfunc(func,None,arg1,arg2,...) #repeat infinitely