파이썬에서 do-while 루프를 모방합니까?


797

파이썬 프로그램에서 do-while 루프를 에뮬레이트해야합니다. 불행히도 다음과 같은 간단한 코드는 작동하지 않습니다.

list_of_ints = [ 1, 2, 3 ]
iterator = list_of_ints.__iter__()
element = None

while True:
  if element:
    print element

  try:
    element = iterator.next()
  except StopIteration:
    break

print "done"

"1,2,3, done"대신 다음 출력을 인쇄합니다.

[stdout:]1
[stdout:]2
[stdout:]3
None['Traceback (most recent call last):
', '  File "test_python.py", line 8, in <module>
    s = i.next()
', 'StopIteration
']

'반복 중지'예외를 포착하고 while 루프를 올바르게 중단하려면 어떻게해야합니까?

그러한 것이 필요한 이유의 예는 아래 의사 코드로 표시됩니다.

상태 머신:

s = ""
while True :
  if state is STATE_CODE :
    if "//" in s :
      tokens.add( TOKEN_COMMENT, s.split( "//" )[1] )
      state = STATE_COMMENT
    else :
      tokens.add( TOKEN_CODE, s )
  if state is STATE_COMMENT :
    if "//" in s :
      tokens.append( TOKEN_COMMENT, s.split( "//" )[1] )
    else
      state = STATE_CODE
      # Re-evaluate same line
      continue
  try :
    s = i.next()
  except StopIteration :
    break

4
음 .. 그건 적절한 "휴가"가 아닙니다. 그것은 단순히 "영원히"입니다. "True"와 "break"의 문제점은 무엇입니까?
S.Lott 2016

70
S. 로트 : 그의 질문은 파이썬에서 어떻게 구현할 것인가 에 대한 것이 확실하다 . 따라서 그의 코드가 완전히 정확하다고는 생각하지 않습니다. 또한, 그는 할 일에 매우 가까워 ... "영원한"루프의 끝에서 자신이 헤어져야하는지 여부를 점검하고 있습니다. "영원히"하지 않습니다.
Tom

4
그래서 ... 초기 예제 코드는 실제로 아무런 문제없이 작동하며 그 역 추적을 얻지 못합니다. 그것은 휴식 조건이 반복자 소진 인 do while 루프에 대한 적절한 관용구입니다. 일반적으로 s=i.next()None 대신 설정 하고 루프를 처음으로 쓸모 없게 만드는 대신 초기 작업을 수행 할 수 있습니다.
언더런

3
@underrun 불행히도, 게시물에는 사용중인 Python 버전이 태그되어 있지 않습니다. 원본 스 니펫은 Python 언어 자체의 업데이트로 인해 2.7을 사용하여 나에게도 효과적입니다.
Hannele

답변:


985

나는 당신이 무엇을하려고하는지 잘 모르겠습니다. 다음과 같이 do-while 루프를 구현할 수 있습니다.

while True:
  stuff()
  if fail_condition:
    break

또는:

stuff()
while not fail_condition:
  stuff()

목록에있는 내용을 인쇄하기 위해 do while 루프를 사용하려고 무엇을하고 있습니까? 왜 사용하지 않습니까?

for i in l:
  print i
print "done"

최신 정보:

라인 목록이 있습니까? 그리고 계속 반복하고 싶습니까? 어때요?

for s in l: 
  while True: 
    stuff() 
    # use a "break" instead of s = i.next()

그게 당신이 원하는 것과 비슷한 것 같습니까? 코드 예제를 사용하면 다음과 같습니다.

for s in some_list:
  while True:
    if state is STATE_CODE:
      if "//" in s:
        tokens.add( TOKEN_COMMENT, s.split( "//" )[1] )
        state = STATE_COMMENT
      else :
        tokens.add( TOKEN_CODE, s )
    if state is STATE_COMMENT:
      if "//" in s:
        tokens.append( TOKEN_COMMENT, s.split( "//" )[1] )
        break # get next s
      else:
        state = STATE_CODE
        # re-evaluate same line
        # continues automatically

1
상태 머신을 만들어야합니다. 상태 머신에서 CURRENT 문을 다시 평가하는 것은 일반적인 경우이므로 다음 항목을 반복하지 않고 '계속'해야합니다. 내가 이러한 일을하는 방법을 모른다 'L에서의 위해'반복 :( 루프, '계속'에가있는 동안 할 일을 다시 평가합니다 마지막에 반복을 현재 항목을 선택합니다.
grigoryvp

당신은 당신이 목록에서 당신의 장소를 추적해야한다는 것을 의미합니까? 그렇게하면 같은 상태로 돌아 왔을 때 중단 한 곳을 찾을 수 있습니까? 좀 더 컨텍스트를 제공하십시오. 목록에 색인을 사용하는 것이 더 나을 것 같습니다.
Tom

고맙습니다, 의사 코드에 댓글을 달았습니다 ... 어떤 상태에 있든 같은 방식으로 "//"를 처리하는 것처럼 보이기 때문에 예제가 좋지 않은 것 같습니다. 또한 주석을 처리하는 실제 코드입니까? 슬래시가있는 문자열이 있으면 어떻게합니까? 즉 : print "blah // <-당신을 엉망으로 만드는가?"
Tom

4
파이썬에 do-while 루프가 없다는 것은 부끄러운 일입니다. 파이썬은 DRY입니까?
Kr0e

43
공식적인 입장 / 정의에 대해서는 PEP 315 를 참조하십시오 . "언어 사용자는 do-while 루프가 적절했을 때 내부 중단과 함께 while-True 양식을 사용하는 것이 좋습니다."
dtk

311

do-while 루프를 에뮬레이트하는 매우 간단한 방법은 다음과 같습니다.

condition = True
while condition:
    # loop body here
    condition = test_loop_condition()
# end of loop

do-while 루프의 주요 특징은 루프 바디가 항상 한 번 이상 실행되고 조건이 루프 바디의 하단에서 평가된다는 것입니다. 여기에 표시된 제어 구조는 예외 또는 break 문이 필요없는 두 가지를 모두 수행합니다. 하나의 추가 부울 변수를 소개합니다.


11
항상 추가 부울 변수를 추가하지는 않습니다. 상태를 테스트 할 수있는 이미 존재하는 것이 종종 있습니다.
martineau

14
내가이 솔루션을 가장 좋아하는 이유는 다른 조건을 추가하지 않고 여전히 한주 기 일뿐이므로 도우미 변수에 대한 좋은 이름을 선택하면 전체 구조가 분명합니다.
Roberto

4
참고 :이 방법은 원래의 질문을 다루지 만이 방법은을 사용하는 것보다 유연성이 떨어 break집니다. 특히, AFTER test_loop_condition()에 필요한 로직이 있다면 , 일단 완료되면 실행해서는 안됩니다 if condition:. BTW condition는 모호합니다. 더 설명 : more또는 notDone.
ToolmakerSteve

7
@ToolmakerSteve 동의하지 않습니다. 나는 break루프에서 거의 사용하지 않으며 내가 유지하는 코드에서 루프를 만날 때 루프가 루프없이 작성되었을 수 있다는 것을 알게되었습니다. 제시된 솔루션은 IMO 입니다. 파이썬에서 do while 구문을 나타내는 가장 명확한 방법입니다.
nonsensickle

1
이상적으로, 조건은 같은 뭔가 설명, 지정됩니다 has_no_errors또는 end_reached루프가 시작할 것 (이 경우while not end_reached
.. JosiahYoder-비활성화를 제외하고

75

아래 코드는 유용한 구현이 될 수 있습니다. vs 내가 이해 한대로

따라서이 경우 항상 루프를 한 번 이상 통과해야합니다.

first_pass = True
while first_pass or condition:
    first_pass = False
    do_stuff()

2
정답입니다. 또한 try / except 블록에서 안전하게 사용하기 위해 break를 피 합니다.
Zv_oDD

jit / optimizer는 첫 번째 패스 후 first_pass를 다시 테스트하지 않습니까? 그렇지 않으면, 그것은 성가신,하지만 아마도 약간의 성능 문제가 될 것입니다
markhahn

2
@markhahn 이것은 매우 작지만 그러한 세부 사항을 신경 쓰면 루프에서 2 개의 부울을 뒤집을 수 있습니다 while condition or first_pass:. 그런 다음 condition항상 먼저 평가되고 전체 first_pass는 두 번만 평가됩니다 (첫 번째 및 마지막 반복). condition루프하기 전에 원하는 것을 초기화하는 것을 잊지 마십시오 .
pLOPeGG

HM, 흥미로운 사실은 조건을 초기화 할 필요가 없으므로 코드를 최소한으로 변경하지 않아도되도록 의도적으로 다른 방법을 선택했습니다. 그것은 당신의 요점을
알았습니다

33

예외가 발생하면 루프가 중단되므로 루프 외부에서도 처리 할 수 ​​있습니다.

try:
  while True:
    if s:
      print s
    s = i.next()
except StopIteration:   
  pass

코드의 문제는 break내부의 동작이 except정의 되어 있지 않다는 것입니다. 일반적으로 break하나의 레벨 만 올라갑니다. 예를 들어 break내부 tryfinally(있는 경우) try루프 밖으로 나가지 않습니다.

관련 PEP : http://www.python.org/dev/peps/pep-3136
관련 질문 : 중첩 루프 해제


8
원치 않는 예외를 포착하지 않도록 예외를 던질 것으로 예상되는 try 문 안에 만 포함시키는 것이 좋습니다.
Paggas

7
@PiPeep : RTFM, EAFP를 검색하십시오.
vartec

2
@PiPeep : 문제가 없습니다. 명심하십시오. 일부 언어에 해당되는 것은 다른 언어에 해당되지 않을 수도 있습니다. 파이썬은 예외를 집중적으로 사용하도록 최적화되어 있습니다.
vartec

5
break and continue는 try / except / finally 문의 모든 절에 완벽하게 정의되어 있습니다. 그들은 단순히 그것들을 무시하고 포함하는 while 또는 for 루프의 다음 반복에서 벗어나거나 적절하게 이동합니다. 루핑 구문의 구성 요소는 while 및 for 문에만 관련이 있으며 가장 안쪽 루프에 도달하기 전에 클래스 또는 def 문을 실행하면 구문 오류를 트리거합니다. if, with 및 try 문을 무시합니다.
ncoghlan

1
.. 이것은 중요한 경우입니다
javadba

33
do {
  stuff()
} while (condition())

->

while True:
  stuff()
  if not condition():
    break

기능을 수행 할 수 있습니다.

def do_while(stuff, condition):
  while condition(stuff()):
    pass

그러나 1) 추악합니다. 2) 조건은 하나의 매개 변수가있는 함수이어야하며 물건으로 채워져 있어야합니다 ( 클래식 while 루프를 사용 하지 않는 유일한 이유 입니다).


5
글쓰기 while True: stuff(); if not condition(): break는 아주 좋은 생각입니다. 감사합니다!
녹 티스 스카이 타워 September

2
@ ZeD, 왜 1) 못생긴? 그것은 꽤 괜찮습니다, IMHO
Sergey Lossev

@SergeyLossev 사이에 많은 '물건'코드가있는 경우 처음에는 무한 루프로 나타나기 때문에 프로그램의 논리를 파악하기가 어려울 것입니다.
exic

16

다음은 코 루틴을 사용하는 다른 패턴의 더 크레이지 한 솔루션입니다. 코드는 여전히 매우 유사하지만 한 가지 중요한 차이점이 있습니다. 출구 조건이 전혀 없습니다! 코 루틴 (코 루틴 체인)은 데이터 공급을 중단하면 중지됩니다.

def coroutine(func):
    """Coroutine decorator

    Coroutines must be started, advanced to their first "yield" point,
    and this decorator does this automatically.
    """
    def startcr(*ar, **kw):
        cr = func(*ar, **kw)
        cr.next()
        return cr
    return startcr

@coroutine
def collector(storage):
    """Act as "sink" and collect all sent in @storage"""
    while True:
        storage.append((yield))

@coroutine      
def state_machine(sink):
    """ .send() new parts to be tokenized by the state machine,
    tokens are passed on to @sink
    """ 
    s = ""
    state = STATE_CODE
    while True: 
        if state is STATE_CODE :
            if "//" in s :
                sink.send((TOKEN_COMMENT, s.split( "//" )[1] ))
                state = STATE_COMMENT
            else :
                sink.send(( TOKEN_CODE, s ))
        if state is STATE_COMMENT :
            if "//" in s :
                sink.send(( TOKEN_COMMENT, s.split( "//" )[1] ))
            else
                state = STATE_CODE
                # re-evaluate same line
                continue
        s = (yield)

tokens = []
sm = state_machine(collector(tokens))
for piece in i:
    sm.send(piece)

위의 코드는 모든 토큰을 튜플로 수집 하며 원래 코드 와 는 tokens차이가 없다고 가정 합니다..append().add()


4
오늘 파이썬 3.x에서 어떻게 작성 하시겠습니까?
녹 티스 스카이 타워 September

13

내가 한 방법은 다음과 같습니다.

condition = True
while condition:
     do_stuff()
     condition = (<something that evaluates to True or False>)

이것은 단순한 해결책 인 것 같습니다. 여기서 그것을 보지 못했다는 것에 놀랐습니다. 이것은 분명히 반전 될 수 있습니다

while not condition:

기타


당신은 "내가 이미 여기에서 보지 못해서 놀랐다"고 말하지만 2010 년 powderflask의 솔루션과는 다른 점을 보지 못합니다. 정확히 동일합니다. ( "condition = true while condition : # loop body here condition = test_loop_condition () # loop of end")
cslotty

10

try 문을 포함하는 do-while 루프

loop = True
while loop:
    generic_stuff()
    try:
        questionable_stuff()
#       to break from successful completion
#       loop = False  
    except:
        optional_stuff()
#       to break from unsuccessful completion - 
#       the case referenced in the OP's question
        loop = False
   finally:
        more_generic_stuff()

또는 '최종'절이 필요하지 않은 경우

while True:
    generic_stuff()
    try:
        questionable_stuff()
#       to break from successful completion
#       break  
    except:
        optional_stuff()
#       to break from unsuccessful completion - 
#       the case referenced in the OP's question
        break

7
while condition is True: 
  stuff()
else:
  stuff()

8
으. 휴식 시간을 사용하는 것보다 상당히 추한 것 같습니다.
mattdm

5
그것은 영리하지만 stuff함수이거나 코드 본문을 반복해야합니다.
녹 티스 스카이 타워 September

12
필요한 것은 암시 while condition:되기 때문 is True입니다.
martineau

2
해당 변수가 현재 정의되어 있지 않기 때문에 condition의 내부 변수에 의존하는 경우 실패합니다 stuff().
yo '

5
condition! = True 일 때 마지막 반복에서 동일한 논리가 아닙니다. 최종 코드를 호출합니다. A와 어디 않지만 , 먼저 다음 검사 조건을 한 번 다시 실행하기 전에 코드를 호출합니다. Do While : 블록을 한 번 실행합니다. 그런 다음 확인하고 다시 실행하십시오 .이 답변 : 확인하고 다시 실행하십시오. 그런 다음 코드 블록을 한 번 실행하십시오 . 큰 차이!
Zv_oDD

7

빠른 해킹 :

def dowhile(func = None, condition = None):
    if not func or not condition:
        return
    else:
        func()
        while condition():
            func()

다음과 같이 사용하십시오.

>>> x = 10
>>> def f():
...     global x
...     x = x - 1
>>> def c():
        global x
        return x > 0
>>> dowhile(f, c)
>>> print x
0

3

왜 안 해?

for s in l :
    print s
print "done"

?


1
상태 머신을 만들어야합니다. 상태 머신에서 CURRENT 문을 다시 평가하는 것은 일반적인 경우이므로 다음 항목을 반복하지 않고 '계속'해야합니다. 'for s in l :'iteration :(. do-while 루프에서 'continue'는 현재 항목, 반복이 끝날 때
마다 재평가합니다

그런 다음 상태 머신에 대한 의사 코드를 정의 할 수 있으므로 최고의 파이 토닉 솔루션을 제안 할 수 있습니까? 상태 머신에 대해 많이 알지 못하며 (아마도 유일한 것은 아닙니다) 알고리즘에 대해 조금 알려 주면 더 쉽게 도울 수 있습니다.
Martin

a = fun () while a == 'zxc': sleep (10) a = fun ()
harry

이것은 완전히 부울 조건을 확인하는 시점 그리워
javadba

1

이것이 도움이되는지보십시오 :

예외 처리기 내부에 플래그를 설정하고 s에서 작업하기 전에 확인하십시오.

flagBreak = false;
while True :

    if flagBreak : break

    if s :
        print s
    try :
        s = i.next()
    except StopIteration :
        flagBreak = true

print "done"

3
를 사용 while not flagBreak:하고 제거 하여 단순화 할 수 있습니다 if (flagBreak) : break.
martineau

1
나는 이름이 붙은 변수를 피한다 flag-True value 또는 False value의 의미를 유추 할 수 없다. 대신 done또는을 사용하십시오 endOfIteration. 코드는로 바뀝니다 while not done: ....
IceArdor

1

리소스를 사용할 수 없거나 예외가 발생하는 비슷한 상황에서 루핑하는 시나리오에 있다면 다음과 같은 것을 사용할 수 있습니다

import time

while True:
    try:
       f = open('some/path', 'r')
    except IOError:
       print('File could not be read. Retrying in 5 seconds')   
       time.sleep(5)
    else:
       break

0

나에게 전형적인 while 루프는 다음과 같습니다.

xBool = True
# A counter to force a condition (eg. yCount = some integer value)

while xBool:
    # set up the condition (eg. if yCount > 0):
        (Do something)
        yCount = yCount - 1
    else:
        # (condition is not met, set xBool False)
        xBool = False

상황에 따라 다른 조건 세트를 반복하기 위해 while 루프 내에 for..loop를 포함시킬 수도 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.