2009-12-23 5 views
13

파이썬의 반복기는 훌륭하고 때로는 실제로 foreach 루프가 아닌 C 스타일의 루프를 원합니다. 예를 들어, 시작 날짜와 종료 날짜가 있으며 해당 범위의 매일 작업을 수행하려고합니다. 나는 물론, while 루프와 함께이 작업을 수행 할 수 있습니다파이썬에는 for 루프와 동등한 루프가 있습니다 (foreach가 아님)

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

이 작동하지만 (C 또는 C 기반 언어) 3 선 대신 1과 나는 종종 자신이 증분 라인을 작성 잊고 찾아, 특히 루프 바디가 꽤 복잡한 경우. 파이썬에서 더 우아하고 오류를 일으키지 않는 방법이 있습니까?

답변

30

그것을 할 수있는 우아하고 파이썬 방법은 자체 발전기에서 날짜 범위의 개념을 캡슐화 코드에서 그 생성기를 사용하는 것입니다 :

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 날짜 시간 작업, 그래서 우리는 필요가 없습니다 우리 자신을 만들 수는 있지만 적어도 캡슐화 된 방식으로 한 번만 할 수 있습니다.

+1

+1은 ** 실제로 작동하는 유일한 답변 일뿐만 아니라 **뿐만 아니라 그것이 올바른 것임을 주장합니다. 진심으로, 그냥 * 잘 보이는 대답을 투표하지 마십시오 * –

-2

xrange는 반복자를 반환하기 때문에 range는 1에서 last-1까지의 전체 정수 범위를 포함하는 실제 목록 개체를 생성하므로 실제로 반복 할 목적으로 xrange 범위를 사용해야합니다.

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

또한,이 열거되고, 증가하는 수와 컬렉션의 가치, 즉를 얻을 것이다 열거 객체를 반환 : 당신이 원하는 모든)에 대한 루프 간단 때 분명히 덜 효율적이다

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

결과 :

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 

인쇄 :

0 a 
1 b 
2 c 
+2

-1 시험 답변 당신이 게시하기 전에. 결과는'TypeError : 정수가 필요합니다'입니다. 'xrange()'의 모든 인수는 정수 여야합니다. –

+0

'xrange'는 iterator를 반환 할 때'irange'라는 이름이어야합니다. 반면'range'는 항상리스트를 반환해야합니다; 'xrange'에 대한 유일한 제약 조건은'next = start; 다음 = 다음 + 단계; until next == end' 즉,'start'는'step'에'__add__' 가능해야하고 결과는'__cmp__''로 끝나야합니다. –

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'을 잊어 버리기 때문에 오류가 발생하기 쉽습니다. 내게는 무한 루프를 만든 다음 종료 조건을 확인하는 것이 더 자연스러운 것처럼 보입니다.

+5

WTF? 왜 단지 xrange (시작, 끝)에서'for를 사용하지 않는가? '? –

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)