在Python中模拟C风格的for循环
(我知道这个标题可能会引起争议)
Python在设计上选择让for
循环使用明确的可迭代对象,这样在大多数情况下代码会变得简单很多。
不过,有时候如果你的测试案例和更新函数比较复杂,构造一个可迭代对象就会变得很麻烦,因此我发现自己写了以下的while循环:
val = START_VAL
while <awkward/complicated test case>:
# do stuff
...
val = <awkward/complicated update>
这样做的问题在于,更新的代码放在while
块的底部,这意味着如果我想在其中某个地方使用continue
,我就必须:
重复写复杂或尴尬的更新代码,另外
还要冒着忘记这部分代码的风险,导致我的代码进入无限循环
我可以选择手动创建一个复杂的迭代器:
def complicated_iterator(val):
while <awkward/complicated test case>:
yeild val
val = <awkward/complicated update>
for val in complicated_iterator(start_val):
if <random check>:
continue # no issues here
# do stuff
但我觉得这样写太冗长和复杂了。Stack Overflow上的朋友们有没有更简单的建议?
对评论的回应:
@Glenn Maynard:是的,我忽略了那个答案。如果有办法用一行代码完成的事情,写五行是很糟糕的……特别是在这种经常出现的情况下(循环是图灵完备程序的常见特征)。
对于那些寻找具体例子的人:假设我在使用一个自定义的日期库。我的问题是,如何用Python表达这个:
for (date = start; date < end; date = calendar.next_quarter_end(date)):
if another_calendar.is_holiday(date):
continue
# ... do stuff...
6 个回答
那这样怎么样:
date = start
while date < end:
if not another_calendar.is_holiday(date):
# ... do stuff...
date = calendar.next_quarter_end(date)
不过,如果你经常使用那种特定的写法,最好还是先定义好这个生成器,然后像你在问题中那样重复使用它。
实际上,因为这两种语言不同,你不可能把C语言中的每一种写法都对应到Python中更简洁的写法。这就像说你有一种压缩算法,可以对所有随机输入都一样有效。
我有点困惑:你有一个复杂的 while 表达式,还有一个复杂的 next 表达式,但它们却能很好地适应 C 语言的 for 循环?这让我觉得不太合理。
我建议你使用自定义迭代器的方法。你可能会发现迭代器还有其他用处,而且把迭代过程封装起来也是一种很好的编程习惯。
更新:根据你的例子,我肯定会制作一个自定义迭代器。对我来说,日历能够生成一系列季度日期是非常自然的事情:
class Calendar:
# ...
def quarters(self, start, end):
"""Generate the quarter-start dates between `start` and `end`."""
date = start
while date < end:
yield date
date = self.next_quarter_end(date)
for date in calendar.quarters(start, end):
if another_calendar.is_holiday(date):
continue
# ... do stuff...
这看起来是你日历类提供的一个很棒的抽象,我敢打赌你会不止一次用到它。
这是我能想到的最好办法:
def cfor(first,test,update):
while test(first):
yield first
first = update(first)
def example(blah):
print "do some stuff"
for i in cfor(0,lambda i:i<blah,lambda i:i+1):
print i
print "done"
我希望Python能有一种闭包表达式的语法。
编辑:另外,注意你只需要定义一次cfor(而不是你那个complicated_iterator
函数)。