通常情况下,人们需要无限循环直到达到某种条件.例如,如果我想继续收集随机整数,直到我找到一个数字== n,然后我打破.我这样做:
import random
rlist = []
n = ...
low, high = ..., ...
while True:
num = random.randint(low, high)
if num == n:
break
rlist.append(num)
Run Code Online (Sandbox Code Playgroud)
这很有效,但非常笨重.有一个更多的pythonic替代品使用iter:
iter(o [,sentinel])
返回一个迭代器对象.根据第二个参数的存在,第一个参数的解释非常不同.[...]如果给出第二个参数sentinel,则o必须是可调用对象.在这种情况下创建的迭代器将为每个对其
next()方法的调用调用o而不带参数; 如果返回的值等于sentinel,则会引发StopIteration,否则返回该值.
上面的循环可以替换为
import random
from functools import partial
f = partial(random.randint, low, high)
rlist = list(iter(f, 10))
Run Code Online (Sandbox Code Playgroud)
要将此原则扩展到已创建的列表,需要稍作更改.我需要定义一个像这样的部分函数:
f = partial(next, iter(x)) # where x is some list I want to keep taking items from until I hit a sentinel
Run Code Online (Sandbox Code Playgroud)
其余的保持不变,但这种方法与while循环的主要警告是我不能应用泛型布尔条件.
例如,我不能应用"生成数字,直到遇到大于1000的第一个偶数".
底线是这样的:是否有另一种替代while循环并iter支持回调sentinel?
如果你想要通用布尔条件,那么iter(object, sentinel)你的需求就没有足够的表现力.itertools.takewhile()相反,它似乎或多或少是你想要的:它需要一个迭代器,并在给定的谓词停止为真时将其切断.
rlist = list(itertools.takewhile(lambda x: x >= 20, inputlist))
Run Code Online (Sandbox Code Playgroud)
顺便说一下,partial并不是非常Pythonic,也不是itertools.GvR正在记录为不喜欢高阶函数式编程(请注意reduce3.0 中从内置到模块成员的降级).像"优雅"和"可读"这样的属性在旁观者的眼中,但如果你在最纯粹的意义上寻找Pythonic,你需要while循环.
| 归档时间: |
|
| 查看次数: |
389 次 |
| 最近记录: |