여러 루프에서 벗어나는 방법?


479

다음 코드가 주어지면 작동하지 않습니다.

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break 2 #this doesn't work :(
        if ok.lower() == "n": break
    #do more processing with menus and stuff

이 작업을 수행하는 방법이 있습니까? 또는 입력 루프에서 벗어나기 위해 한 가지 검사를 한 다음 외부 루프를 검사하여 사용자가 만족하는 경우 모두 함께 나눕니 까?


87
왜 파이썬은 'break (n)'을 가지고 있지 않습니까? 여기서 n은 원하는 레벨 수입니다.
Nathan

2
C ++은 goto많은 루프에 깊숙히 자리 잡고 있다면 여기에 좋습니다
Drake Johnson

답변:


512

내 첫 번째 본능은 중첩 루프를 함수로 리팩터링하고 사용 return하는 것입니다.


3
get_input_yn () 함수가 다른 곳에서도 유용 할 것이기 때문에 이것이 내가 생각한 또 다른 생각입니다.
Matthew Scharley

96
이 특정 경우에 동의했지만 일반적인 경우 '내포 된 루프가 있습니다. 리팩토링'은 의미가 없을 수 있습니다.
quick_dry

return을 사용하는 대신 yield를해야 할 때 예외를 사용하는 것이 더 쉬울 수 있지만, 그런 경우에는 itertools.islice ()를 사용해야합니다.
로버트 킹

5
일반적으로 내부 루프를 자체 메서드로 리팩터링하여 계속하려면 true를, 외부 루프를 중단하려면 false를 반환합니다. condition1 : / MyLoop2 (params)가 아닌 경우 : break. 대안은 두 레벨에서 테스트되는 부울 플래그를 설정하는 것입니다. more = True / while condition1 이상 : / while condition2 이상 : / if stopCondition : more = False / break / ...
ToolmakerSteve

7
사용하기 위해 노력하는 return것이 올바른 방법 이라는 데 동의합니다 . 그리고 파이썬선에 따르면 "평면이 중첩보다 낫다"고 추론 합니다. 여기에는 세 가지 수준의 중첩이 있으며, 이것이 시작되면 중첩을 줄이거 나 적어도 전체 중첩을 자체 기능으로 추출해야 할 때입니다.
Lutz Prechelt

240

짧은 또 다른 접근법이 있습니다. 단점은 외부 루프 만 끊을 수 있지만 때로는 정확히 원하는 루프입니다.

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

이것은 for / else 구문에 설명되어 있습니다 : 왜 파이썬은 for 및 while 루프 후에 'else'를 사용합니까?

주요 통찰력 : 외부 루프가 항상 끊어지는 것처럼 보입니다 . 그러나 내부 루프가 끊어지지 않으면 외부 루프도 끊어지지 않습니다.

continue문은 여기 마법이다. for-else 절에 있습니다. 내부 휴식이없는 경우 발생하는 정의의해 . 이 상황 continue에서 외피가 깔끔하게 우회됩니다.


6
@eugeney 왜 안돼? 첫 번째 브레이크는 내부 루프에서 나옵니다.
Navin

5
@eugeney 여기에 뭔가 빠진 것 같습니다. 예를 게시 할 수 있습니까?
Navin

4
계속하기 전에 갈 수있는 @Mingliang.
Baldrickk

1
이것을 Raymond Hettinger 비디오 youtu.be/OSGv2VnC0go?t=971 에서 가져 왔으며 for 루프에 첨부 된 "else"문을 "no_break"로 읽으면 이해하기 쉬워집니다.
Ambareesh

2
이것은 영리합니다. :-) 그러나 간단하지는 않습니다. 솔직히 말해서, 파이썬에서 break 또는 break (n)이라는 레이블을 유지하라는 주장에 확신이 없습니다. 해결 방법이 더 복잡해집니다.
rfportilla

148

PEP 3136 은 분류 된 중단 / 계속을 제안합니다. Guido "이 기능을 요구하기에 너무 복잡한 코드는 매우 드물기 때문에" 거부했습니다 . PEP는 (예외 기술과 같은) 몇 가지 해결 방법을 언급하지만 Guido는 반환을 사용하기 위해 리팩토링하는 것이 대부분의 경우 더 간단하다고 생각합니다.


73
비록 리팩터링 / return이 일반적으로가는 길이 지만, 나는 간결한 간결한 ' break 2'서술문이 그다지 의미가 있는 몇 가지 사례를 보았습니다 . 또한 리팩터링 / return은 동일하게 작동하지 않습니다 continue. 이러한 경우, 숫자 나누기와 계속은 작은 함수로 리팩토링하거나 예외를 발생 시키거나 각 네스트 레벨에서 깨지도록 플래그를 설정하는 복잡한 논리보다 더 쉽게 따르고 복잡하지 않습니다. 귀도가 거부 한 것은 부끄러운 일입니다.
James Haigh

10
break; break좋은 것.
PyRulez

5
@Jeyekomon 문제는 이것이 문제가되기 위해 3 개 이상의 중첩 루프가 필요 없다는 것입니다. 2 개의 중첩 루프는 일반적입니다
Jon

6
"이 기능을 필요로하는 복잡한 코드는 매우 드물다". 그러나이 복잡한 코드를 사용하는 경우 레이블이 지정된 루프가 없으면 break모든 루프를 통해 수동으로 전달해야하기 때문에 훨씬 복잡해집니다 . 바보.
BallpointBen

3
분명히 5 분 동안 만 게시물을 편집 할 수 있습니다 (6 회). 그래서, 여기 내가 편집 한 게시물이 있습니다 : 내 2 센트 : Perl은 break (그러나 '마지막'이라고 부릅니다)와 '다음'이라고 레이블을 지정하여 다음 반복으로 직접 진행합니다. 전혀 드물지 않습니다-나는 항상 그것을 사용합니다. 저는 Python을 처음 접했고 이미 필요합니다. 또한 번호가 매겨진 나누기는 리팩토링에 끔찍할 것입니다. 분리하려는 루프에 레이블을 지정하는 것이 좋으며, break <label>을 사용하여 중단하려는 루프를 명시 적으로 지정하십시오.
John Deighan

119

첫째, 일반적인 논리가 도움이됩니다.

어떤 이유로 종료 조건을 해결할 수없는 경우 예외는 대체 계획입니다.

class GetOutOfLoop( Exception ):
    pass

try:
    done= False
    while not done:
        isok= False
        while not (done or isok):
            ok = get_input("Is this ok? (y/n)")
            if ok in ("y", "Y") or ok in ("n", "N") : 
                done= True # probably better
                raise GetOutOfLoop
        # other stuff
except GetOutOfLoop:
    pass

이 특정 예에서는 예외가 필요하지 않을 수 있습니다.

반면, 문자 모드 응용 프로그램에는 종종 "Y", "N"및 "Q"옵션이 있습니다. "Q"옵션의 경우 즉시 종료해야합니다. 더 예외적입니다.


4
진지하게 예외는 매우 저렴하며 관용적 인 파이썬은 많은 것을 사용합니다. 사용자 정의를 정의하고 던지는 것도 매우 쉽습니다.
Gregg Lind

13
재미있는 생각. 나는 그것을 사랑하든 싫어하든 찢어졌다.
Craig McQueen

8
이 솔루션은 두 가지 변형을 개별적으로 보여 주면 더 도움이됩니다. (1) 플래그 ()를 사용합니다 done. (2) 예외를 제기. 그것들을 단일 솔루션으로 병합하면 복잡해 보입니다. 미래의 독자들을 위해 : 여기에 관련된 모든 줄을 done사용 GetOutOfLoop(Exception)하거나 , 정의 하고 올리거나 제외하십시오.
ToolmakerSteve

4
일반적으로 try-blocks 이외의 다른 용도로는 try-block을 사용하는 것이 매우 어려워집니다. Try-block은 오류 처리를 위해 특별히 설계되었으며 이상한 제어 흐름에 사용하는 것은 문체 적으로 그리 좋지 않습니다.
nobillygreen

3
@ tommy.carstensen 말도 안 돼요; 새로운 예외 서브 클래스를 정의하고 올리는 것 (답변에 표시)과 사용자 정의 메시지를 Exception생성자 (예 :)에 전달하는 raise Exception('bla bla bla')것은 파이썬 2와 파이썬 3 모두에서 유효합니다. 전자는이 경우에 바람직하지 않습니다. 우리의 except블록을 잡으려고 모든 예외를하지만 특별한 예외 우리는 루프를 종료하기 위해 사용하고 있습니다. 우리가 제안한대로 일을하고 코드의 버그로 인해 예기치 않은 예외가 발생하면 의도적으로 루프를 종료하는 것과 동일하게 잘못 취급됩니다.
Mark Amery

54

함수로 리팩토링하는 것이 일반적으로 이런 상황에 가장 적합한 방법이라는 데 동의하는 경향이 있지만, 중첩 루프에서 실제로 벗어날 필요가있는 경우 @ S.Lott에서 설명한 예외 제기 접근법의 흥미로운 변형이 있습니다. 파이썬의 with문장을 사용하여 예외 발생을 조금 더 멋지게 만듭니다. 다음을 사용하여 새 컨텍스트 관리자를 정의하십시오 (한 번만 수행).

from contextlib import contextmanager
@contextmanager
def nested_break():
    class NestedBreakException(Exception):
        pass
    try:
        yield NestedBreakException
    except NestedBreakException:
        pass

이제이 컨텍스트 관리자를 다음과 같이 사용할 수 있습니다.

with nested_break() as mylabel:
    while True:
        print "current state"
        while True:
            ok = raw_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": raise mylabel
            if ok == "n" or ok == "N": break
        print "more processing"

장점 : (1) 약간 더 깔끔하고 (명시적인 시도 제외 블록은 없음) (2) Exception사용할 때마다 사용자 정의 된 서브 클래스를 얻습니다 nested_break. Exception매번 자신의 서브 클래스 를 선언 할 필요가 없습니다 .


40

먼저 입력을 가져오고 유효성을 검사하는 프로세스를 만드는 것도 고려할 수 있습니다. 해당 함수 내에서 올바른 경우 값을 반환하고 그렇지 않은 경우 while 루프 에서 계속 회전 할 수 있습니다 . 이것은 본질적으로 해결 한 문제를 방지하며 일반적으로보다 일반적인 경우 (여러 루프에서 발생)에 적용 할 수 있습니다. 코드 에이 구조를 유지해야하고 부기 부울을 다루고 싶지 않은 경우 ...

다음과 같은 방식으로 goto 를 사용할 수도 있습니다 ( 여기서 April Fools 모듈 사용 ).

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

나는 "고토를 사용하지 말아야한다"는 것을 알고 있지만, 이런 경우에는 이상하게 작동합니다.


1
INTERCAL의 COME FROM 명령과 같은 것이면 아무것도 없습니다.
1800 INFORMATION

3
나는 농담을 좋아하지만 스택 오버플로의 요점은 좋은 코드를 홍보하는 것이므로 투표해야합니다 :(
Christian Oudard

13
좋은 코드로 인정받을만큼 깨끗하고 읽기 쉬운 솔루션이라고 생각합니다. :)
JT Hurley

1
@JTHurley 아니오 이것은 깨끗하고 읽을 수 없습니다. 내 말은, 이 예제 에서는 깨끗하고 읽을 수있는 것처럼 보일 수 있지만 실제 시나리오에서는 goto가 성가신 혼란을 만듭니다 . (또한 이것은 sooo anti-pythonic입니다 ...)
Alois Mahdal

2
goto는 나쁜 담당자를 얻습니다. 모든 전문 코더는 제 의견으로는 올바르게 처리 할 수 ​​있습니다.
Albert Renshaw

33

'루프 브레이커'로 사용할 새 변수를 소개하십시오. 먼저 무언가 (False, 0 등)를 할당 한 다음 외부 루프 내부에서 벗어나기 전에 값을 다른 것으로 변경하십시오 (True, 1, ...). 루프가 종료되면 '부모'루프에서 해당 값을 확인하십시오. 보여 드리겠습니다 :

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

무한 루프가 있다면 이것이 유일한 방법입니다. 다른 루프의 경우 실행 속도가 훨씬 빠릅니다. 중첩 루프가 많은 경우에도 작동합니다. 모두 또는 몇 개만 종료 할 수 있습니다. 끝없는 가능성! 이것이 도움이 되었기를 바랍니다!


22

함수로 리팩토링하지 않고 여러 개의 중첩 된 루프를 해제하려면 내장 된 StopIteration 예외 와 함께 "시뮬레이트 된 goto 문"을 사용하십시오 .

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

중첩 루프를 해제하기위한 goto 문 사용에 대한 이 논의 를 참조하십시오 .


1
이것은 예외를 처리하기 위해 자신의 클래스를 만드는 것보다 훨씬 좋으며 매우 깨끗합니다. 내가 이것을해서는 안되는 이유가 있습니까?
mgjk 2018 년

실제로 StopIteration은 생성기에 사용되지만 일반적으로 캐치되지 않은 StopIteration 예외는 없다고 생각합니다. 따라서 좋은 해결책처럼 보이지만 어쨌든 새로운 예외를 만드는 데 실수는 없습니다.
코왈 스키

1
나에게 가장 적합하고 간단한 솔루션
Alexandre Huat

16

keeplooping=True
while keeplooping:
    #Do Stuff
    while keeplooping:
          #do some other stuff
          if finisheddoingstuff(): keeplooping=False

또는 그런 것. 내부 루프에서 변수를 설정하고 내부 루프가 종료 된 직후 외부 루프에서 변수를 확인하여 적절한 경우 중단합니다. 파이썬 바보가 아닌 April Fool의 농담 모듈을 사용하는 것이 마음에 들지 않는다면 GOTO 방법과 비슷합니다.


이것은 일종의 플래그 설정입니다!
SIslam

나는 그것이 매우 좋은 해결책이라고 생각합니다.
코왈 스키

13

가장 좋은 방법은 아니지만 제 생각에는 가장 좋은 방법입니다.

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

나는 당신이 여기에서도 재귀를 사용하여 무언가를 해결할 수 있다고 확신하지만, 그것이 당신에게 좋은 옵션이라면 나는 몰라.


이것은 나에게 맞는 솔루션이었습니다. 내 유스 케이스는 OP와 매우 다릅니다. 순열을 찾기 위해 본질적으로 동일한 데이터를 두 번 반복하고 있었으므로 두 개의 while 루프를 분리하고 싶지 않았습니다.
브라이언 피터슨

9

두 가지 조건이 모두 충족된다면 왜 계속 반복하지 않는가? 나는 이것이 더 파이썬적인 방법이라고 생각합니다.

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

그렇지 않습니까?

모두 제일 좋다.


왜 안돼 while dejaVu:? 어쨌든 true로 설정했습니다.
Matthew Scharley

이봐, 작동한다! 나는 True두 개의 루프를 건너 뛸 두 가지 조건 에서 생각 했지만 하나만으로 충분합니다.
Mauro Aspé

2
@ MatthewScharley 이것이 이것이 중첩 루프에서 작동한다는 것을 보여주는 것이라고 생각합니다.
처리

@ MauroAspé 이것은 OP가 요청하는 것을 정확하게하지 않을 것입니다. 여전히 전체 외부 루프를 실행하지만 목표는 나머지 코드를 깰 경우 코드가 실행되지 않는 것입니다.
yamm

@yamm if not dejaVu: break하단에 a로 해결되지 않아서 메인 루프를 종료 할 수 있습니까? 나는 해결책이 요구 된 것에 가장 가깝다고 생각합니다. +1
milcak

8

루프 논리를 반복자로 생성하여 루프 변수를 생성하고 완료되면 반환합니다. 여기에는 이미지가 없거나 이미지를 놓을 때까지 행 / 열로 이미지를 배치하는 간단한 것입니다.

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

이것은 복잡한 루프 논리와 처리를 분리하는 이점이 있습니다 ...


3

이 경우 다른 사람들이 지적한 것처럼 기능적 분해가 진행됩니다. 파이썬 3의 코드 :

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break

3

파이썬 while ... else구조에는 많은 코드 변경 / 추가없이 이중 중단을 시뮬레이션하는 데 사용할 수 있는 숨겨진 트릭 이 있습니다. 본질적으로 while조건이 거짓이면 else블록이 트리거됩니다. 예외 continue나 블록을 break트리거 하지 않습니다 else. 자세한 내용은 " Python while statement의 Else 절 "에 대한 답변 또는 while on doc (v2.7)에 대한 답변을 참조하십시오 .

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

유일한 단점은 이중 분리 조건을 조건으로 이동해야한다는 것입니다 while(또는 플래그 변수 추가). 루프의 완료 후에 블록이 트리거 for되는 루프 에도이 변형이 존재합니다 else.


이것은 이중 중단의 요구 사항을 충족시키지 못하는 것 같습니다. 주어진 문제에 대해서는 작동하지만 실제 질문에는 작동하지 않습니다.
Dakkaron

@Dakkaron 코드를 올바르게 이해 했습니까? 이 코드는 실제로 OP 질문을 해결하고 요청과 유사하게 중단됩니다. 그러나 여러 루프에서 벗어나지 않지만 else 절을 ​​사용하여 나누기를 두 배로 늘릴 필요를 대체하십시오.
holroy

내 이해에서 질문은 How to break out of multiple loops in Python?있었고 "답변하지 않았다, 다른 것을 시도하십시오." 나는 그것이 OP의 정확한 예를 수정한다는 것을 알고 있지만 그들의 질문에 대답하지는 않습니다.
Dakkaron

@ Dakkaron, 코드 아래의 문제 설명을 참조하십시오. 제 생각에는 OPs 질문에 실제로 대답합니다.
holroy

2

반복을 단일 레벨 루프로 줄이는 또 다른 방법은 파이썬 참조에 지정된대로 생성기를 사용하는 것입니다.

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

루프 레벨에 관계없이 레벨을 조정할 수 있습니다

단점은 더 이상 단일 레벨 만 깰 수 없다는 것입니다. 전부 아니면 아무것도 아니야

또 다른 단점은 while 루프에서는 작동하지 않는다는 것입니다. 나는 원래이 답변을 파이썬 에 게시하고 싶었습니다 -모든 루프에서`break` 하지만 불행히도 이것은이 복제본으로 닫힙니다.


1
while 루프에서도 작동하므로 생성기를 이해하는 것이 아니라 def (수율 포함)로 작성하면됩니다.
Veky

예, PyCon의 발표자는 @RobertRossney의 대답조차도 진정한 Pythonic은 아니지만 발전기는 여러 루프를 끊는 올바른 방법 이라고 주장합니다 . (전체 비디오를 보는 것이 좋습니다!)
Post169

2

여기에 오는 나의 이유는 내가 외부 루프와 내부 루프를 가지고 있기 때문입니다.

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

  do some other stuff with x

보시다시피 실제로 다음 x로 이동하지 않고 대신 다음 y로 이동합니다.

내가 이것을 해결하기 위해 찾은 것은 단순히 배열을 두 번 실행하는 것이 었습니다.

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

for x in array:
  do some other stuff with x

나는 이것이 OP의 질문의 특정 사례라는 것을 알고 있지만, 문제를 단순하게 유지하면서 누군가가 자신의 문제에 대해 다르게 생각하는 데 도움이되기를 희망하여 게시하고 있습니다.


이것은 아마도 파이썬이 아닙니다. 배열의 유형은 무엇입니까? 아마도 목록에 무엇이 포함되어 있습니까? int가 포함되어 있어도 array.pop (x)는 원하는 것을 수행하지 않을 것입니다.
Veky

그건 좋은 지적이야. 내가 참조한 코드를 찾을 수 없습니다. 이것을 읽는 사람이라면 array.pop (i) "배열에서 인덱스 i가있는 항목을 제거하고 반환합니다." 파이썬 문서에 따라. 따라서이 코드가 예상대로 작동하려면 배열에서 항목 x의 인덱스를 가져와야합니다. 예상되는 것을 수행하는 array.remove (x) 함수도 있습니다. 위의 답변을 수정하여 해당 오류를 수정합니다. array.remove (x)는 찾은 x의 첫 번째 인스턴스 만 제거하므로 두 번째 배열에는 중복 항목이 없다고 가정합니다.
Nathan Garabedian

좋아, 그럼 알아 그렇다면 단순히 break대신에 사용 continue하면 원하는 것을 할 수 있습니까? :-)
Veky

예, 효율성과 명확성을 위해이 예제에서 계속하는 대신 break를 사용하고 싶을 것입니다. :)
나단 가라 베 디안

2

무한 발전기를 사용해보십시오.

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff

2

함수를 사용하여 :

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

주석 처리하여 위의 코드를 실행하십시오 return.

어떤 기능을 사용하지 않고 :

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

이제 위의 코드를 먼저 실행 한 다음 break아래에서 한 번에 하나씩 포함 된 각 줄을 주석 처리하여 실행 하십시오.


2

여러 개의 루프를 하나의 깨지기 쉬운 루프로 바꾸는 쉬운 방법은 numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

값을 명시 적으로 반복 할 수있는 것과는 반대로 객체를 색인화해야하지만, 최소한 간단한 경우에는 제안 된 대부분의 답변보다 약 2-20 배 더 단순 해 보입니다.


2
# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on

1

아마도 기능과 같은 리팩토링을 선호하지 않는다면 아래와 같은 작은 트릭은

while 루프 조건을 제어하기 위해 1 개의 break_level 변수를 추가했습니다.

break_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level

1

변수 (예 : break_statement ) 를 정의한 다음 2 중단 조건이 발생 하면 변수 를 다른 값으로 변경 한 후 if 문에서 사용하여 두 번째 루프에서 벗어날 수도 있습니다.

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break

그러나 내면의 관심 수준보다 높은 각 수준에서 해당 변수를 스캔해야합니다. 언어에 성능 측면에서 GoTo 명령이 없다는 것이 정말 좋지 않습니다.
Anatoly Alekseev

1

파이썬의 함수는 코드 중간에 바로 작성 될 수 있으며, 읽기 및 쓰기 nonlocal또는 global선언을 위해 주변 변수에 투명하게 액세스 할 수 있음을 상기하고 싶습니다 .

따라서 함수를 "깨질 수있는 제어 구조"로 사용하여 반환하려는 장소를 정의 할 수 있습니다.

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4

1

두 가지 방법으로 솔루션

예를 들면 :이 두 행렬이 같거나 같습니까?
행렬 1과 행렬 2는 같은 크기, n, 2 차원 행렬입니다.

첫 번째 솔루션 , 기능이없는

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

두 번째 해결책 , 기능과 함께
이 내 사건에 대한 최종 해결책이다

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

좋은 하루 보내세요!


1
# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff

0

희망적으로 이것은 도움이됩니다 :

x = True
y = True
while x == True:
    while y == True:
         ok = get_input("Is this ok? (y/n)") 
         if ok == "y" or ok == "Y":
             x,y = False,False #breaks from both loops
         if ok == "n" or ok == "N": 
             break #breaks from just one

0

작동하는 것으로 보이는 구현은 다음과 같습니다.

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

유일한 단점 break_은 루프 전에 정의 해야 한다는 것 입니다.


0

언어 수준에서이 작업을 수행 할 방법이 없습니다. 일부 언어에는 다른 언어가 있으며, 다른 언어에는 논쟁이 있지만 파이썬은 그렇지 않습니다.

가장 좋은 옵션은 다음과 같습니다.

  1. 외부 루프에 의해 점검되는 플래그를 설정하거나 외부 루프 조건을 설정하십시오.

  2. 루프를 함수에 넣고 return을 사용하여 모든 루프를 한 번에 나눕니다.

  3. 논리를 재구성하십시오.

1987 년부터 프로그래머 인 Vivek Nagarajan에게 크레딧 제공


기능 사용

def doMywork(data):
    for i in data:
       for e in i:
         return 

플래그 사용

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break

-3

이전과 비슷하지만 더 컴팩트합니다. (부울은 숫자 일뿐입니다)

breaker = False #our mighty loop exiter!
while True:
    while True:
        ok = get_input("Is this ok? (y/n)")
        breaker+= (ok.lower() == "y")
        break

    if breaker: # the interesting part!
        break   # <--- !

2
이것은 이전 버전과 비교할 때보기 흉한 모양이며 코드를 이해하기 어렵게 만듭니다. 또한 잘못되었습니다. 실제로 입력이 허용되는지 확인하고 1 루프 후에 중단됩니다.
Eric

-3

이 질문은 특정 루프를 뚫기위한 표준 질문이되었으므로 예제를 사용하여 대답을하고 싶습니다 Exception.

다중 루프 구조에는 루프 브레이킹이라는 레이블이 없지만 사용자 정의 예외 를 사용하여 선택한 특정 루프로 나눌 수 있습니다. 기본 6 번호 시스템에서 최대 4 자리까지 모든 숫자를 인쇄하는 다음 예를 고려하십시오.

class BreakLoop(Exception):
    def __init__(self, counter):
        Exception.__init__(self, 'Exception 1')
        self.counter = counter

for counter1 in range(6):   # Make it 1000
    try:
        thousand = counter1 * 1000
        for counter2 in range(6):  # Make it 100
            try:
                hundred = counter2 * 100
                for counter3 in range(6): # Make it 10
                    try:
                        ten = counter3 * 10
                        for counter4 in range(6):
                            try:
                                unit = counter4
                                value = thousand + hundred + ten + unit
                                if unit == 4 :
                                    raise BreakLoop(4) # Don't break from loop
                                if ten == 30: 
                                    raise BreakLoop(3) # Break into loop 3
                                if hundred == 500:
                                    raise BreakLoop(2) # Break into loop 2
                                if thousand == 2000:
                                    raise BreakLoop(1) # Break into loop 1

                                print('{:04d}'.format(value))
                            except BreakLoop as bl:
                                if bl.counter != 4:
                                    raise bl
                    except BreakLoop as bl:
                        if bl.counter != 3:
                            raise bl
            except BreakLoop as bl:
                if bl.counter != 2:
                    raise bl
    except BreakLoop as bl:
        pass

출력을 인쇄 할 때 단위 위치가 4 인 값은 절대 얻지 않습니다.이 경우 BreakLoop(4)동일한 루프에서 발생하여 잡은 루프에서 벗어나지 않습니다 . 마찬가지로 10 개의 장소에 3이있을 때마다를 사용하여 세 번째 루프로 나눕니다 BreakLoop(3). 백자리에 5가 BreakLoop(2)있으면를 사용하여 두 번째 루프로 나누고 천 자리에 2가 있으면마다를 사용하여 첫 번째 루프로 나눕니다 BreakLoop(1).

간단히 말해서, 내부 루프에서 예외 (내장 또는 사용자 정의)를 발생시키고 제어를 재개하려는 위치의 루프에서 예외를 포착하십시오. 모든 루프에서 벗어나려면 모든 루프 외부에서 예외를 포착하십시오. (나는이 경우를 보여주지 않았다).

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