12

从函数创建无限迭代器的惯用方法是什么?例如

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

会产生 100 个随机数

4

2 回答 2

17

您想要一个不断产生值的迭代器,直到您停止向它询问新值?只需使用

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())
于 2012-11-30T14:19:27.960 回答
8

每次我看到iter2 个参数时,我都需要挠头并查看文档以弄清楚到底发生了什么。正因为如此,我可能会自己动手:

def call_forever(callback):
    while True:
        yield callback()

或者,正如 Jon Clements 在评论中所述,您可以使用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
于 2012-11-30T14:34:38.890 回答