Делает Python, имеют любого для эквивалентного цикла (не foreach)

Итераторы Python являются большими и все, но иногда я действительно хочу C-стиль для цикла - не цикл foreach. Например, у меня есть дата начала и дата окончания, и я хочу сделать что-то в течение каждого дня в том диапазоне. Я могу сделать это с некоторое время циклом, конечно:

    current = start
    while current <= finish:
        do_stuff(current)
        current += timedelta(1)

Это работает, но это - 3 строки вместо 1 (в C или языках на базе С), и я часто забываю для записи строки постепенного увеличения, особенно если тело цикла довольно сложно. Существует ли более изящное и меньше подверженного ошибкам способа сделать это в Python?

12
задан EMP 23 December 2009 в 04:40
поделиться

3 ответа

Элегантный и питонический способ сделать это - инкапсулировать идею диапазона дат в свой собственный генератор, а затем использовать этот генератор в своем коде:

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

Это похоже на ответ о диапазоне , за исключением того, что встроенный диапазон не будет работать с датами, поэтому мы должны создать свой собственный, но, по крайней мере, мы можем сделать это только один раз в инкапсулированном виде.

29
ответ дан 2 December 2019 в 05:03
поделиться

Только ради итерации, на самом деле следует использовать xrange за пределами диапазона, так как xrange просто вернет итератор, в то время как диапазон создаст реальный объект списка, содержащий весь целочисленный диапазон от первого до последнего-1 (что, очевидно, менее эффективно, когда все, что вам нужно, это простой цикл):

for i in xrange(current,finish+1, timedelta(1)):
    do_stuff(i)

Кроме того, есть перечисление, которое возвращает объект перечисления, который будет давать инкрементирующий счетчик и значение коллекции, i. e.:

l = ["a", "b", "c"]
for ii, value in enumerate(l):
    print ii, value

Результат:

0 a
1 b
2 c
-2
ответ дан 2 December 2019 в 05:03
поделиться

Сделать это компактно на Python нелегко, так как одна из основных концепций, стоящих за языком, не позволяет делать задания на сравнения.

Для чего-то сложного, например, для даты, я думаю, что ответ Неда замечательный, но для более простых случаев, я нашел очень полезную функцию 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

Я нашел ее менее склонной к ошибкам, так как легко, как вы сказали, забыть "текущий += 1". Мне кажется более естественным сделать бесконечный цикл, а затем проверить условие завершения.

2
ответ дан 2 December 2019 в 05:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: