使用带有sentinel的iter()来替换while循环

时间:2017-07-14 14:53:59

标签: python generator

通常情况下,人们需要无限循环直到达到某个条件。例如,如果我想继续收集随机整数,直到我找到一个数字== n,然后我打破。我这样做:

import random

rlist = []
n = ...
low, high = ..., ...
while True:
    num = random.randint(low, high)
    if num == n:
        break
    rlist.append(num)

这很有效,但非常笨重。使用iter有更多的pythonic替代方案:

  

iter(o [,sentinel])

     

返回一个迭代器对象。第一个论点是   根据第二个的存在,解释非常不同   论点。 [...]如果是第二个论点,   给定sentinel,然后o必须是可调用对象。迭代器   在这种情况下创建的将调用o,每次调用都没有参数   它的next()方法;如果返回的值等于sentinel,   将引发StopIteration,否则将返回该值。

上面的循环可以替换为

import random
from functools import partial

f = partial(random.randint, low, high)
rlist = list(iter(f, 10))

要将此原则扩展到已创建的列表,需要稍作更改。我需要定义一个像这样的部分函数:

f = partial(next, iter(x)) # where x is some list I want to keep taking items from until I hit a sentinel

其余的保持不变,但这种方法与while循环的主要警告是我不能应用泛型布尔条件

例如,我不能应用"生成数字,直到遇到第一个大于1000的偶数"。

底线是:是否有另一种替代while循环和iter支持回调哨兵?

1 个答案:

答案 0 :(得分:5)

如果您需要通用布尔条件,那么iter(object, sentinel)表达不足以满足您的需求。相反,itertools.takewhile()似乎或多或少是你想要的:它需要一个迭代器,并在给定的谓词停止为真时将其切断。

rlist = list(itertools.takewhile(lambda x: x >= 20, inputlist))

顺便说一下,partial不是非常Pythonic,itertools也不是。reduce。 GvR记录为不喜欢高阶函数式编程(注意ParameterExpression<String>[] searchStrings = new ParameterExpression[10]; 从内置降级到3.0中的模块成员)。像“优雅”和“可读”这样的属性在旁观者的眼中,但如果你在最纯粹的意义上寻找 Pythonic ,你需要while循环。