Python 有类似于 for 循环的语法吗(不是 foreach)
Python的迭代器虽然很好用,但有时候我真的想要一个像C语言那样的for循环,而不是foreach循环。比如说,我有一个开始日期和一个结束日期,我想对这个范围内的每一天做一些事情。当然,我可以用while循环来实现:
current = start
while current <= finish:
do_stuff(current)
current += timedelta(1)
这样是可以的,但这需要三行代码,而在C语言或类似的语言中只需要一行。我经常会忘记写增加计数的那一行,尤其是当循环里的内容比较复杂的时候。那么在Python中有没有更优雅、更不容易出错的方法呢?
4 个回答
1
这个方法在紧急情况下可以用:
def cfor(start, test_func, cycle_func):
"""A generator function that emulates the most common case of the C for
loop construct, where a variable is assigned a value at the begining, then
on each next cycle updated in some way, and exited when a condition
depending on that variable evaluates to false. This function yields what
the value would be at each iteration of the for loop.
Inputs:
start: the initial yielded value
test_func: called on the previous yielded value; if false, the
the generator raises StopIteration and the loop exits.
cycle_func: called on the previous yielded value, retuns the next
yielded value
Yields:
var: the value of the loop variable
An example:
for x in cfor(0.0, lambda x: x <= 3.0, lambda x: x + 1.0):
print x # Obviously, print(x) for Python 3
prints out
0.0
1.0
2.0
3.0
"""
var = start
while test_func(var):
yield var
var = cycle_func(var)
2
在Python中,要把事情做得简洁一点并不容易,因为这个语言的一个基本概念就是不能在比较中进行赋值。
对于一些复杂的情况,比如日期,我觉得Ned的回答非常好。但对于简单的情况,我发现itertools.count()这个函数非常有用,它可以返回连续的数字。
>>> import itertools
>>> begin = 10
>>> end = 15
>>> for i in itertools.count(begin):
... print 'counting ', i
... if i > end:
... break
...
counting 10
counting 11
counting 12
counting 13
counting 14
counting 15
counting 16
我觉得这样更不容易出错,因为正如你所说的,容易忘记'current += 1'。对我来说,做一个无限循环,然后检查结束条件似乎更自然。
29
优雅且符合Python风格的做法是把日期范围的概念放在一个自己的生成器里,然后在你的代码中使用这个生成器:
import datetime
def daterange(start, end, delta):
""" Just like `range`, but for dates! """
current = start
while current < end:
yield current
current += delta
start = datetime.datetime.now()
end = start + datetime.timedelta(days=20)
for d in daterange(start, end, datetime.timedelta(days=1)):
print d
输出结果是:
2009-12-22 20:12:41.245000
2009-12-23 20:12:41.245000
2009-12-24 20:12:41.245000
2009-12-25 20:12:41.245000
2009-12-26 20:12:41.245000
2009-12-27 20:12:41.245000
2009-12-28 20:12:41.245000
2009-12-29 20:12:41.245000
2009-12-30 20:12:41.245000
2009-12-31 20:12:41.245000
2010-01-01 20:12:41.245000
2010-01-02 20:12:41.245000
2010-01-03 20:12:41.245000
2010-01-04 20:12:41.245000
2010-01-05 20:12:41.245000
2010-01-06 20:12:41.245000
2010-01-07 20:12:41.245000
2010-01-08 20:12:41.245000
2010-01-09 20:12:41.245000
2010-01-10 20:12:41.245000
这和关于range
的回答类似,不过内置的range
不能处理日期时间,所以我们需要自己创建一个。不过至少我们可以把这个过程封装起来,只需要做一次。