在哨兵中使用iter()替换while循环 [英] Using iter() with sentinel to replace while loops

查看:74
本文介绍了在哨兵中使用iter()替换while循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常情况下,需要无限循环直到达到某种条件.例如,如果我要继续收集随机整数,直到找到一个== n的数字,然后我将其破坏.我会这样做:

Oftentimes the case arises where one would need to loop indefinitely until a certain condition has been attained. For example, if I want keep collecting random integers until I find a number == n, following which I break. I'd do this:

import random

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

这可行,但是很笨重.使用 iter :

And this works, but is quite clunky. There is a much more pythonic alternative using iter:

iter(o [,哨兵])

返回一个迭代器对象.第一个参数是 解释的差异很大,具体取决于第二个的存在 争论. [...]如果是第二个论点, 如果指定了哨兵,则o必须是可调用对象.迭代器 在这种情况下创建的每个调用将不带任何参数的o 其next()方法;如果返回的值等于哨兵, StopIteration将被引发,否则将返回该值.

Return an iterator object. The first argument is interpreted very differently depending on the presence of the second argument. [...] If the second argument, sentinel, is given, then o must be a callable object. The iterator created in this case will call o with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.

上面的循环可以替换为

import random
from functools import partial

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

要将此原理扩展到已创建的列表,需要进行一些更改.我需要定义这样的部分函数:

To extend this principle to lists that have already been created, a slight change is needed. I'll need to define a partial function like this:

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

其余部分保持不变,但是与while循环相比,此方法的主要警告是我无法应用通用布尔条件.

The rest remains the same, but the main caveat with this approach versus the while loop is I cannot apply generic boolean conditions.

例如,我无法应用生成数字,直到遇到第一个大于1000的偶数".

For example, I cannot apply a "generate numbers until the first even number greater than 1000 is encountered".

最重要的是:while循环和iter是否有另一种支持回调哨兵的选择?

The bottom line is this: Is there another alternative to the while loop and iter that supports a callback sentinel?

推荐答案

如果需要通用布尔条件,则iter(object, sentinel)不能充分满足您的需求.相比之下,itertools.takewhile()似乎或多或少是您想要的:它需要一个迭代器,并在给定谓词停止为真时将其切断.

If you want generic boolean conditions, then iter(object, sentinel) is insufficiently expressive for your needs. itertools.takewhile(), in contrast, seems to be more or less what you want: It takes an iterator, and cuts it off once a given predicate stops being true.

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

顺便说一句,partial不是Python风格的,itertools也不是. GvR被记录为不喜欢高阶函数式编程(请注意,reduce在3.0中从内置降级为模块成员). 优雅"和可读"之类的属性在旁观者的眼中,但是如果您从最纯粹的意义上寻找 Pythonic ,则需要while循环.

Incidentally, partial is not very Pythonic, and neither is itertools. GvR is on record as disliking higher-order functional-style programming (note the downgrading of reduce from built-in to a module member in 3.0). Attributes like "elegant" and "readable" are in the eye of the beholder, but if you're looking for Pythonic in the purest sense, you want the while loop.

这篇关于在哨兵中使用iter()替换while循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆