Python : 외부 루프에서 다음 반복으로 계속


135

파이썬의 외부 루프에서 다음 반복을 계속할 수있는 내장 방법이 있는지 알고 싶었습니다. 예를 들어 다음 코드를 고려하십시오.

for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            continue
    ...block1...

이 continue 문이 jj 루프를 종료하고 ii 루프의 다음 항목으로 이동하기를 원합니다. 다른 방법으로 (플래그 변수를 설정하여)이 논리를 구현할 수 있지만 쉬운 방법이 있습니까? 아니면 너무 많이 요구하는 것과 같은가요?


11
실제로 파이썬에는 작동하는 goto 문이 있습니다 : entrian.com/goto . 그것은 4 월 바보의 농담으로 발표되었지만 :-) 작동해야합니다.
codeape

3
오, 그 농담을 사용하지 마십시오! 놀랍도록 영리하지만 나중에 코드에 넣으면 슬플 것입니다.
Ned Batchelder

답변:


71
for i in ...:
    for j in ...:
        for k in ...:
            if something:
                # continue loop i

일반적으로 여러 레벨의 루핑이있을 때 break 가없는 경우 (현재 루프 바로 위가 아닌 상위 루프 중 하나를 계속하려는 경우) 다음 중 하나를 수행 할 수 있습니다.

탈출하려는 루프를 함수로 리팩토링

def inner():
    for j in ...:
        for k in ...:
            if something:
                return


for i in ...:
    inner()

단점은 이전에 범위에 있던 일부 변수를 해당 새 함수에 전달해야 할 수도 있다는 것입니다. 매개 변수로 매개 변수를 전달하고 객체에 인스턴스 변수를 만들거나 (이 함수에 맞는 새 객체를 만드는 경우) 전역 변수, 단일 톤 (ehm, ehm)을 지정할 수 있습니다.

또는 inner중첩 함수로 정의 하고 필요한 것을 캡처하도록 할 수 있습니다 (느려질 수 있습니까?).

for i in ...:
    def inner():
        for j in ...:
            for k in ...:
                if something:
                    return
    inner()

예외 사용

철학적으로, 이것은 예외적 인 경우이며, 필요한 경우 구조화 된 프로그래밍 빌딩 블록을 통해 프로그램 흐름을 깨뜨립니다.

장점은 단일 코드를 여러 부분으로 나눌 필요가 없다는 것입니다. 파이썬으로 작성하는 동안 디자인하는 계산의 종류라면 좋습니다. 이 초기 시점에 추상화를 도입하면 속도가 느려질 수 있습니다.

이 접근법의 나쁜 점은 통역사 / 컴파일러 작성자는 일반적으로 예외가 예외적이라고 가정하고 그에 따라 최적화한다는 것입니다.

class ContinueI(Exception):
    pass


continue_i = ContinueI()

for i in ...:
    try:
        for j in ...:
            for k in ...:
                if something:
                    raise continue_i
    except ContinueI:
        continue

이를 위해 특별한 예외 클래스를 생성하여 실수로 다른 예외를 침묵시킬 위험이 없도록하십시오.

완전히 다른 것

나는 여전히 다른 해결책이 있다고 확신합니다.


두 번째 루프를 다른 방법으로 옮길 생각이 없었습니다. 나는 느려지고있다
pmccallum

1
나에게 예외를 사용하는 것이 이것을 달성하는 좋은 방법입니다. 나는 @ user7610에 동의한다- "철학적으로, 이것은 예외이다."
Renato Byrro 2016 년

좋은 오래된 부울 변수와 If 문?
MrR

OP는 "다른 방법으로 (플래그 변수를 설정하여)이 논리를 구현할 수 있습니다"[...] "에 대한 대안 솔루션을 찾고 있습니다.
user7610

149
for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            break
    else:
        ...block1...

Break 내부 루프가 중단되고 block1이 실행되지 않습니다 (내부 루프가 정상적으로 종료 된 경우에만 실행 됨).


1
안녕하세요, 이와 같은 다른 옵션이 있습니까? block1에서 다른 for 루프를 수행하고 싶기 때문에 코드가 3 레벨 깊어집니다. 이상한 상황.
Sahas

3
나에게 이것은 다른 방식으로 가장 잘 접근 할 수있는 for 루프로 무언가를 시도하는 것처럼 들린다.
Kimvais

예. 그래서 for..else 구조를 사용하지 않았습니다. 이제 여전히 루프가 필요하지만 플래그 변수를 사용하여 제어를 전환합니다.
Sahas

3
for...else혼동 될 수 있지만 종종 유용한 구문입니다. else이 문맥에서 "휴식 없음" 을 의미 한다는 것을 기억하십시오 .
asmeurer

이것은 단지 두 레이어의 루프로 제한되는 것 같습니다. 세 개의 중첩 루프가있는 일부 코드를 업데이트해야하며 새로운 고객 요구 사항은 특정 상황에서 가장 안쪽 루프가 가장 바깥 쪽 루프의 다음 반복을 계속해야 함을 의미합니다. 귀하의 제안이 해당 시나리오에 적용되지 않는다고 가정합니다.
kasperd

42

다른 언어에서는 루프에 레이블을 지정하고 레이블이 지정된 루프에서 벗어날 수 있습니다. Python Enhancement Proposal (PEP) 3136은 이것을 Python에 추가 할 것을 제안 했지만 Guido는 거부했습니다 .

그러나이 기능을 요구하기에 너무 복잡한 코드는 매우 드물기 때문에 거부합니다. 대부분의 경우 깨끗한 코드를 생성하는 기존 해결 방법이 있습니다 (예 : 'return'사용). 코드의 선명도가 리팩토링으로 인해 리턴을 사용할 수있는 드문 실제 사례가 있지만 두 가지 문제로 상쇄됩니다.

  1. 언어에 복잡성이 영구적으로 추가되었습니다. 이것은 모든 Python 구현뿐만 아니라 모든 소스 분석 도구와 언어에 대한 모든 문서에 영향을 미칩니다.

  2. 이 기능이 올바르게 사용되는 것보다 더 많이 남용 될 것이라는 기대는 코드 선명도의 감소로 이어졌습니다 (이후로 작성된 모든 Python 코드에서 측정 됨). 게으른 프로그래머는 어디에나 있으며, 그것을 알기 전에는 이해할 수없는 코드를 손에 넣을 수 있습니다.

그래서 그것이 당신이 바라는 것이면 운이 좋지 않지만 거기에 좋은 옵션이 있기 때문에 다른 대답 중 하나를보십시오.


4
흥미 롭군 나는 귀도에 동의합니다. 어떤 경우에는 좋지만 남용 될 수 있습니다. 그것을 구현하지 않는 또 다른 이유는 현재 C와 Python 사이에서 포트 코드를주고받는 것이 매우 간단하기 때문입니다. 파이썬이 다른 언어에서 부족한 기능을 찾기 시작하면 더 어려워집니다. 예를 들어 파이썬에서 for 루프에 else 문을 가질 수 있다는 사실을 생각해보십시오. 이렇게하면 코드가 다른 언어로 이식성이 떨어집니다.
eric.frederich

2
모든 우박 Guido 우리
BDFL

4
이것은 좋은 반론보다는 빨간 귀환이지만, 그 행동은 for-else명명 된 루프보다 더 복잡하고 읽기가 더 어려우며 아마도 (오명 한 실수가 아닌 경우) 더 남용 될 것 같습니다. 키워드와 다른 키워드를 사용 else했을 것 resume입니다. 당신 break은 루프에 있고 resume바로 뒤에 있습니까?
ArtOfWarfare

5
이것은 나를 슬프게한다. 나는 어떻게 파이썬을 사랑하고 미워하는지 믿을 수 없다. 너무 아름답지만 너무 wtf.
jlh

5
@jlh 대부분 나를 위해 wtf. 때로는 합법적 인 목적이 아닌 다른 것이되기를 원한다고 생각합니다. 이것은 좋은 예입니다. 외부 루프를 자주 끊어야 할 필요성이 생겼습니다.
Rikaelus

14

나는 당신이 이런 식으로 할 수 있다고 생각합니다 :

for ii in range(200):
    restart = False
    for jj in range(200, 400):
        ...block0...
        if something:
            restart = True
            break
    if restart:
        continue
    ...block1...

4
-1 : OP는 그들이 이와 같은 일을 할 수 있다는 것을 알고 있다고 분명히 말했으며, 이것은 답이 더 지저분한 버전처럼 보입니다 (8 개월 이전의 답변보다 더 오래되었으므로 수락 한 것을 놓쳤을 수 없었습니다) 대답).
ArtOfWarfare

10
허용 대답은 본 적이 아닌 경우 명확 for, else전 (그리고 나는 그것이 어떻게 작동하는지 머리의 상단을 기억할 수없는에도 대부분의 사람들을 생각한다).
asmeurer

3

이 작업을 수행하는 가장 쉬운 방법 중 하나는 "continue"를 "break"문으로 바꾸는 것입니다.

for ii in range(200):
 for jj in range(200, 400):
    ...block0...
    if something:
        break
 ...block1...       

예를 들어 다음은 정확히 어떻게 진행되는지 확인하는 쉬운 코드입니다.

for i in range(10):
    print("doing outer loop")
    print("i=",i)
    for p in range(10):
        print("doing inner loop")
        print("p=",p)
        if p==3:
            print("breaking from inner loop")
            break
    print("doing some code in outer loop")

2

이런 종류의 문제를 처리하는 또 다른 방법은 Exception ()을 사용하는 것입니다.

for ii in range(200):
    try:
        for jj in range(200, 400):
            ...block0...
            if something:
                raise Exception()
    except Exception:
        continue
    ...block1...

예를 들면 다음과 같습니다.

for n in range(1,4):
    for m in range(1,4):
        print n,'-',m

결과:

    1-1
    1-2
    1-3
    2-1
    2-2
    2-3
    3-1
    3-2
    3-3

m = 3 인 경우 m 루프에서 외부 n 루프로 점프한다고 가정합니다.

for n in range(1,4):
    try:
        for m in range(1,4):
            if m == 3:
                raise Exception()            
            print n,'-',m
    except Exception:
        continue

결과:

    1-1
    1-2
    2-1
    2-2
    3-1
    3-2

참조 링크 : http://www.programming-idioms.org/idiom/42/continue-outer-loop/1264/python


1

무언가를 찾은 다음 내부 반복을 중지하려고합니다. 플래그 시스템을 사용합니다.

for l in f:
    flag = True
    for e in r:
        if flag==False:continue
        if somecondition:
            do_something()
            flag=False

귀하의 솔루션이 다운 보트 된 이유를 모르겠습니다. 누군가가 기본적으로 정확히 같은 것을 게시하고 10 번
공모

나는 stackoverflow에별로 운이 좋지 않다.
Esther

1
어쩌면 이미 여기에 게시 된 것과 똑같은 내용이 있기 때문에 아마도 False:continue... 특이한 형식입니다. 지수가 표준 인 "천연"시스템에서 흔히 발생하는 것처럼, 상당한 양의 평판 포인트를 축적하기 위해 SO에서 몇 번만 운이 좋아야합니다. 어쨌든 내 "최고의"답변은 일반적으로 가장 인기있는 답변입니다.
user7610

0

방금 이런 식으로했습니다. 이것에 대한 나의 해결책은 내부 for 루프를 목록 이해로 대체하는 것이 었습니다.

for ii in range(200):
    done = any([op(ii, jj) for jj in range(200, 400)])
    ...block0...
    if done:
        continue
    ...block1...

여기서 op는 ii와 jj의 조합으로 작동하는 부울 연산자입니다. 필자의 경우 어떤 작업이 true를 반환하면 완료되었습니다.

이것은 실제로 코드를 함수로 나누는 것과 다르지 않지만 "any"연산자를 사용하여 부울 목록에서 논리 OR을 수행하고 논리를 한 줄에 모두 수행하는 것이 흥미 로웠다고 생각했습니다. 또한 함수 호출을 피합니다.

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