Подтвердить что ты не робот

Python: итератор от функции

Что такое идиоматический способ создания бесконечного итератора из функции? Например

from itertools import islice
import random
rand_characters = to_iterator( random.randint(0,256) )
print ' '.join( islice( rand_characters, 100))

будет производить 100 случайных чисел

4b9b3361

Ответ 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