在哨兵中使用iter()替换while循环 [英] Using iter() with sentinel to replace while loops
问题描述
通常情况下,需要无限循环直到达到某种条件.例如,如果我要继续收集随机整数,直到找到一个== 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屋!