파이썬 루프의 'else'절을 어떻게 이해할 수 있습니까?


191

많은 파이썬 프로그래머는 아마도 while루프와 for루프 의 구문에 선택적 else:절이 포함되어 있다는 것을 인식하지 못합니다 .

for val in iterable:
    do_something(val)
else:
    clean_up()

else절의 본문은 특정 종류의 정리 작업에 적합한 위치이며 루프가 정상적으로 종료 될 때 실행됩니다. 즉, 절 과 함께 루프를 종료 return하거나 절을 break건너 뜁니다 else. continue실행 후 종료 합니다. 난 그냥 때문이 알고 그것을보고 내가 기억하지 못할 수 있기 때문에, (다시 한번) else 절이 실행됩니다.

항상? 이름에서 알 수 있듯이 루프의 "실패"? 정기적으로 해지됩니까? return?로 루프를 종료하더라도 나는 그것을 보지 않고 완전히 확신 할 수 없습니다.

나는 키워드의 선택에 대한 나의 지속적인 불확실성을 비난한다 else. 내 질문은 "이 키워드가 왜 이런 목적으로 사용 되었는가"(답과 의견을 읽은 후에 만 ​​투표 할 수 있음 )가 아니라 키워드의 의미가 이해되도록 키워드 에 대해 어떻게 생각할 수 else있습니까? 그러므로 기억할 수 있습니까?

나는 이것에 대해 상당한 양의 논의가 있었을 것이라고 확신하며, try성명서의 else:조항 (또한 조회해야 함)과 일관성을 유지하기 위해 선택되었으며 파이썬의 예약어. 아마도 선택의 이유는 else그 기능을 명확히하고 더 기억에 남을 것이지만, 나는 역사적 설명 자체가 아니라 이름을 기능에 연결 한 후입니다.

에 대한 답변 이 질문에 내 질문에 간단히의 중복으로 폐쇄했다, 흥미로운 다시 이야기를 많이 포함되어 있습니다. 내 질문은 다른 초점 ( else키워드 선택과 특정 의미를 연결하는 방법 )이 있지만 어딘가에이 질문에 대한 링크가 있어야한다고 생각합니다.


23
"반복해야 할 것이 있다면 ..."
OneCricketeer

4
이 질문을 작성한 후 지금 기억할 수 있다고 생각합니다 :)
Jasper

11
else수단 기본적으로, "계속 상태가 실패 할 경우". 루프 전통에서 계속 조건은 일반적으로 i < 42이 경우, 당신은으로 그 부분을보실 수 있습니다,if i < 42; execute the loop body; else; do that other thing
njzk2

1
이 모든 사실, 나는 특히 drawoc의 대답처럼,하지만 고려해야 할 또 다른 한가지는 것입니다 다른 사람 도 문법적으로 다소 좋은 의미가 있음을 가능한 키워드입니다. 당신은 마지막으로 / 제외시켰다 / 시도 아마도 제외하고는 / 시도를 알 수 있지만, 그것은 또한이 다른 - 실행 이 코드를 예외가 발생하지 않는 경우. try 절 에서이 코드를 입력 하는 것과 같은 것이 아닌 btw입니다. 예외 처리는 좁은 대상에 가장 적합합니다. 따라서 여기에는 많은 답변에 따라 개념적 의미가 있지만 특정 조건 에서 키워드를 다시 사용 하는 것 같습니다 .
JL Peyret

1
@Falanwe,에 의해 코드가 종료되면 차이가 break있습니다. 정식 유스 케이스는 루프가 무언가를 검색하고 발견하면 중단됩니다. 는 else아무 것도 발견되지 않는 경우에만 실행됩니다.
Alexis

답변:


212

(@Mark Tolonen의 답변에서 영감을 얻었습니다.)

if문은 실행 else의 조건이 false로 평가되면 절을. 동일하게하는 while루프는 false로 상태 평가 될 경우 다른 절을 실행합니다.

이 규칙은 설명 된 동작과 일치합니다.

  • 정상 실행에서 while 루프는 조건이 false로 평가 될 때까지 반복적으로 실행되므로 자연스럽게 루프를 종료하면 else 절이 실행됩니다.
  • break명령문 을 실행할 때 조건을 평가하지 않고 루프를 종료하므로 조건이 false로 평가 될 수 없으며 else 절을 ​​실행하지 않습니다.
  • continue명령문 을 실행할 때 조건을 다시 평가하고 루프 반복이 시작될 때 정상적으로 수행하는 작업을 정확하게 수행합니다. 따라서 조건이 true이면 루프를 계속 유지하지만 false이면 else 절을 ​​실행합니다.
  • 와 같은 루프를 종료하는 다른 방법은 return조건을 평가하지 않으므로 else 절을 ​​실행하지 마십시오.

for루프는 같은 방식으로 동작합니다. 반복자에 더 많은 요소가 있으면 조건을 true로, 그렇지 않으면 false를 고려하십시오.


8
이것은 가장 훌륭한 답변입니다. 루프를 일련의 elif 문처럼 취급하면 else 동작에 자연스러운 논리가 노출됩니다.
Nomenator

1
나는 또한이 답변을 좋아하지만 일련의 elif진술 과 유추하지 않습니다 . 거기에 대답 하지, 그것은 하나의 순 upvote에 있습니다.
Alexis

2
정확히는 아니지만 while 루프는 조건이 False를 충족하기 직전에 조건을 충족시킬 수 있습니다. break이 경우 else조건은 실행되지 않지만 조건은 False입니다. for루프 와 마찬가지로 break마지막 요소에서도 가능합니다.
Tadhg McDonald-Jensen 2016

36

이 방법으로 생각하는 것이 좋습니다. 모든 블록 이 이전 블록 에서 올바르게 진행 되어 완전히 소진 되면 else블록이 항상 실행됩니다 .for

오른쪽 이 맥락에서 어떤 의미하는 것 exception아니, break아니, return. 제어를 가로채는 명령문 forelse블록을 무시합니다.


의 항목을 검색 할 때 일반적인 유스 케이스가 발견되며 iterable, 항목을 찾거나 "not found"다음 else블록을 통해 플래그를 올리거나 인쇄 하는 검색이 호출됩니다 .

for items in basket:
    if isinstance(item, Egg):
        break
else:
    print("No eggs in basket")  

A continue는의 제어를 가로 채지 for않으므로 제어가 else종료 된 후로 진행됩니다 for.


20
아주 좋은 것 같습니다 ...하지만 else상황 올바르게 진행 되지 않으면 절이 실행될 것으로 기대 하지 않습니까? 나는 이미 다시 혼란스러워하고 있습니다 ...
Alexis

"기술적으로, 그것은 [서로 다른 의미 론적으로 비슷하지 않다" "에 대해 당신의 의견에 동의하지 않습니다 else. 왜냐하면 제가 대답else 에서 증명하는 것처럼 for 루프의 어떤 조건도 True로 평가되지 않을 때 실행 되기 때문에
Tadhg McDonald- Jensen

@ TadhgMcDonald-Jensen 또한 루프를 중단 할 수 있습니다 False. 그래서이 방법의 문제 for입니다 깨진는 유스 케이스에 따라 달라집니다.
Moses Koledoye 2016 년

맞다, 나는 어떻게해서 "else"의 영어의 의미 ( else파이썬 에서 다른 용도로 반영 되는가)에 어떤 일이 일어나는지 물어볼 것이다 . else@Moses에 대한 직관적 인 요약을 제공 하지만이 동작을 "else"와 연관시킬 수있는 방법에 대해서는 설명하지 않습니다. 다른 키워드가 사용 된 경우 (예 : 관련 질문에 대한 답변nobreak 에서 언급 한 바와 같이 ) 이해하기 쉽습니다.
Alexis

1
그것은 "올바른 일"과는 아무런 관련이 없습니다. else는 if/ while조건이 false로 평가되거나 for항목이 없을 때 순수하게 실행됩니다 . break포함 루프가 존재합니다 ( else). continue되돌아 가서 루프 조건을 다시 평가합니다.
Mark Tolonen 2016 년

31

언제 if실행 else합니까? 조건이 거짓 인 경우. while/ 와 동일합니다 else. 따라서 while/ elseif거짓으로 평가할 때까지 실제 상태를 계속 유지하는 것으로 생각할 수 있습니다 . A break는 그것을 바꾸지 않습니다. 그것은 평가없이 포함 루프 밖으로 뛰어납니다. 는 else경우에만 실행 평가if / while조건 것은 거짓입니다.

for그 거짓 조건이 반복자를 배출 것을 제외하고, 유사합니다.

continuebreak실행하지 않습니다 else. 그것은 그들의 기능이 아닙니다. 을 break포함하는 루프를 종료합니다. 가 continue루프 상태가 평가된다 함유 루프의 상부로 돌아 간다. 실행 되고 다른 방법 이없는 것은 if/ while를 거짓 으로 평가 하거나 for더 이상 항목이없는 행위입니다 else.


1
당신이 소리가 매우 재치있는 말을하지만, 함께 세 가지 종료 조건을 총괄하는 "까지가 [조건] 거짓 또는 나누기 / 계속"잘못 : 결정적으로는 else루프가로 종료되는 경우 절은 실행 continue(정상적으로)하지만, 종료하면 아닙니다break . 이러한 미묘한 점 때문에 내가 else잡는 것과 그렇지 않은 것을 실제로 파악하려고합니다 .
Alexis

4
@alexis 네, 분명히해야했습니다. 편집했습니다. continue는 else를 실행하지 않지만 루프의 맨 위로 돌아가서 false로 평가 될 수 있습니다.
Mark Tolonen 2016 년

24

이것이 본질적으로 의미하는 바입니다.

for/while ...:
    if ...:
        break
if there was a break:
    pass
else:
    ...

이 일반적인 패턴을 작성하는 것이 더 좋습니다.

found = False
for/while ...:
    if ...:
        found = True
        break
if not found:
    ...

else절은이 경우 실행되지 않습니다 return때문에 return이에 의미로, 잎 기능. 당신이 생각할 수있는 유일한 예외는 finally의 목적이며 항상 실행되도록하는 것입니다.

continue이 문제와 관련이 없습니다. 루프의 현재 반복이 종료되어 전체 루프가 종료 될 수 있으며,이 경우 루프가로 끝나지 않았습니다 break.

try/else 유사하다:

try:
    ...
except:
    ...
if there was an exception:
    pass
else:
    ...

20

루프를 이와 비슷한 구조 (의사 코드)로 생각하면 :

loop:
if condition then

   ... //execute body
   goto loop
else
   ...

좀 더 이해가 될 수 있습니다. 루프는 본질적으로 if조건이 될 때까지 반복 되는 명령문입니다 false. 그리고 이것이 중요한 포인트입니다. 루프는 상태를 확인하고 그것이 상태임을 확인 false하여 else(보통과 마찬가지로)if/else 한 다음 루프가 완료됩니다.

따라서 else 조건이 확인되면 유일한 get이 실행됩니다 . 즉 , 예를 들어 a return또는 a 로 실행 도중 루프 본문을 종료 break하면 조건이 다시 확인되지 않으므로else 되지 않으므로 사례가 실행되지 않습니다.

반면 continue에 A 는 현재 실행을 중지 한 다음 루프 상태를 다시 확인하기 위해 다시 점프하므로이 else시나리오에서 도달 할 수 있습니다.


나는이 답변을 거의 좋아하지만 단순화 할 수 있습니다 : end레이블을 생략 goto loop하고 if몸 안에 넣으십시오 . 어쩌면 넣어내어 쓰기 if의 레이블과 같은 줄에, 그리고 갑자기 아주 많이 시킴으로 빨리 것 같습니다.
Bergi

@ Bergi 예, 그게 좀 더 명확하다고 생각합니다.
Keiwan

15

루프의 나의 잡았다 순간 else내가 의한 이야기보고 때 절이었다 레이몬드 Hettinger 그는이 호출되어 있어야합니다 생각하는 방법에 대한 이야기를 말했다 nobreak. 다음 코드를 살펴보십시오. 어떻게 할 것이라고 생각하십니까?

for i in range(10):
    if test(i):
        break
    # ... work with i
nobreak:
    print('Loop completed')

당신은 무엇을 추측합니까? 글에서 루프에 부딪치지 않은 nobreak경우에만 실행되는 부분입니다 break.


8

일반적으로 다음과 같은 루프 구조를 생각하는 경향이 있습니다.

for item in my_sequence:
    if logic(item):
        do_something(item)
        break

변수 개수가 많은 if/elif문장 과 비슷하려면 :

if logic(my_seq[0]):
    do_something(my_seq[0])
elif logic(my_seq[1]):
    do_something(my_seq[1])
elif logic(my_seq[2]):
    do_something(my_seq[2])
....
elif logic(my_seq[-1]):
    do_something(my_seq[-1])

이 경우 elsefor 루프의 else명령문은 elifs 체인의 명령문 과 동일하게 작동 하며 True로 평가되기 전에 조건이없는 경우에만 실행됩니다. (또는 return예외 와 함께 또는 실행을 중단 ) 내 루프 가이 사양에 맞지 않으면 for: else이 질문을 게시 한 정확한 이유로 사용하지 않기로 선택합니다 . 직관적이지 않습니다.


권리. 그러나 루프가 여러 번 실행되므로이를 for 루프에 적용하는 방법이 어느 정도 확실하지 않습니다. 당신은 명확히 할 수 있습니까?
Alexis

@ Alexis 나는 내 대답을 다시 작성했는데, 지금은 훨씬 명확하다고 생각합니다.
Tadhg McDonald-Jensen 2016

7

다른 사람은 이미의 메커니즘을 설명했다 while/for...else, 그리고 파이썬 3 언어 참조 (참조 권위있는 정의가 있는 동안위해를 )하지만, 여기에 내 개인 니모닉, FWIW입니다. 필자의 열쇠는 이것을 두 부분으로 나누는 것입니다. 하나 else는 루프 조건부와 관련 하여 의미를 이해하는 것과 루프 제어를 이해하는 것입니다.

이해하는 것이 가장 쉬운 방법이라는 것을 알았습니다 while...else.

while당신은 더 많은 항목을 가지고, 물건을, else당신이 부족하면이 작업을 수행

for...else니모닉은 기본적으로 동일합니다 :

for모든 항목, 물건을 수행하지만 else부족하면이 작업을 수행

두 경우 모두 else처리 할 항목이 더 이상없는 경우에만 부품에 도달하고 마지막 항목은 정기적으로 처리됩니다 (예 : 아니요 break또는 return). A continue는 다시 돌아가서 더 이상 항목이 있는지 확인합니다. 이 규칙에 대한 나의 연상 기호는 모두 적용 whilefor:

break노래 나 return노래를 할 때 할 일이 없습니다 else.
그리고 말할 때 continue, 그것은 당신을 위해 "시작 루프"입니다.

- 분명히 의미 "시작하는 루프 다시"와, 우리의 반복자에 더 이상 항목이 있는지 확인 루프의 시작은 그렇게 멀리는 다음과 같이 else우려, continue정말 전혀 역할을하지 않는다.


4
for / else 루프의 일반적인 목적 은 찾고있는 것을 발견하고 멈추고 싶 거나 아이템이 부족 해질 때까지 항목을 검사하는 것이라고 말함으로써 향상 될 수 있다고 제안 합니다. "다른 것"은 "찾은 항목을 찾지 못한 채 항목이 없음"부분을 처리하기 위해 존재합니다.
supercat

@ supercat : 가능하지만 가장 일반적인 용도는 무엇인지 모르겠습니다. 은 else또한 단순히 모든 항목을 완료하고 일을하는 데 사용할 수 있습니다. 예를 들어, 로그 항목 작성, 사용자 인터페이스 업데이트 또는 수행 한 다른 프로세스에 대한 신호 전달이 있습니다. 정말요 또한 일부 코드 조각은 break루프 내부 에서 "성공적인"사례로 끝나고 else반복 중에 적합한 항목을 찾지 못한 "오류"사례를 처리하는 데 사용됩니다 (아마 생각했던 내용 일 수 있음) 의?).
Fabian Fagerholm 2016

1
내가 생각 된 경우였다 정확하게 경우 어디에 "휴식"과 성공적인 경우 종료하고 "다른"핸들 성공의 부족. 루프 내에 "break"가 없으면 "else"코드는 단순히 블록을 둘러싸는 블록의 일부로 루프를 따라갈 수 있습니다.
supercat

루프가 모든 반복 가능한 항목을 중단하지 않고 성공한 경우와 그렇지 않은 경우를 구별해야 할 필요가없는 한. 그런 다음 "완료"코드를 루프 else블록에 넣거나 다른 방법으로 결과를 추적해야합니다. 기본적으로 동의합니다. 사람들이이 기능을 어떻게 사용하는지 모르기 때문에 " else성공 사례 처리"시나리오 또는 " else성공하지 못한 사례 처리"시나리오가 더 일반적 인지 여부를 가정하고 싶지 않습니다 . 그러나 당신은 좋은 지적을 가지고 있으므로 의견을 피하십시오!
Fabian Fagerholm

7

에서 개발 테스트 주도 은 USING 경우 (TDD) 변환 우선 전제 패러다임을, 당신은 조건문의 일반화로 루프를 처리합니다.

간단한 if/else(아니요 elif) 문만 고려하면이 방법은이 구문과 잘 결합됩니다 .

if cond:
    # 1
else:
    # 2

일반화 :

while cond:  # <-- generalization
    # 1
else:
    # 2

훌륭하게.

다른 언어로, 단일 사례에서 수집 사례까지의 TDD 단계에는 더 많은 리팩토링이 필요합니다.


다음은 8thlight 블로그 의 예입니다. .

8thlight 블로그의 링크 된 기사에서 Word Wrap kata는 문자열에 줄 바꿈을 추가하여 ( s아래 스 니펫 의 변수) 주어진 너비 ( length아래 스 니펫 의 변수)에 맞게 만듭니다 . 어느 시점에서 구현은 다음과 같습니다 (Java).

String result = "";
if (s.length() > length) {
    result = s.substring(0, length) + "\n" + s.substring(length);
} else {
    result = s;
}
return result;

현재 실패한 다음 테스트는 다음과 같습니다.

@Test
public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception {
    assertThat(wrap("verylongword", 4), is("very\nlong\nword"));
    }

따라서 조건부로 작동하는 코드가 있습니다. 특정 조건이 충족되면 줄 바꿈이 추가됩니다. 여러 줄 바꿈을 처리하도록 코드를 개선하려고합니다. 이 기사에 제시된 솔루션은 (if-> while) 변환 을 적용 할 것을 제안 하지만 저자는 다음과 같은 의견을 제시합니다.

루프는 else절을 가질 수 없으므로 else경로에서 더 적게 수행 하여 경로 를 제거해야 if합니다. 다시, 이것은 리팩토링입니다.

하나의 테스트 실패 상황에서 코드를 더 많이 변경해야합니다.

String result = "";
while (s.length() > length) {
    result += s.substring(0, length) + "\n";
    s = s.substring(length);
}
result += s;

TDD에서는 테스트를 통과시키기 위해 가능한 한 적은 코드를 작성하려고합니다. Python의 구문 덕분에 다음과 같은 변환이 가능합니다.

에서:

result = ""
if len(s) > length:
    result = s[0:length] + "\n"
    s = s[length:]
else:
    result += s

에:

result = ""
while len(s) > length:
    result += s[0:length] + "\n"
    s = s[length:]
else:
    result += s

6

내가 보는 방식 else:은 루프 끝을 반복 할 때 발생합니다.

만약 당신 break이나 returnraise 당신으로 반복 루프의 끝을지나하지, 당신은 immeadiately 중지, 따라서 else:블록은 실행되지 않습니다. 당신이 경우 continue루프의 끝을지나 여전히 반복 처리가 계속 있기 때문에 바로 다음 반복으로 건너 뜁니다. 루프를 멈추지 않습니다.


1
나는 당신이 무언가에 있다고 생각합니다. 그것은 루프 키워드 이전의 나쁜 옛날에 루핑이 구현되는 방식과 약간 관련이 있습니다. (즉, 수표는 루프 의 맨 아래 에 배치되었으며 goto성공의 맨 위에 표시됩니다.) 그러나 가장 인기있는 답변의 짧은 버전입니다.
alexis

@alexis, 주관적이지만 생각하기가 더 쉬운 표현 방법을 찾으십시오.
Winston Ewert 2016 년

실제로 동의합니다. 더 화려하기 때문에.
알렉시스

4

else절을 루프 구성의 일부로 생각하십시오 . break루프 구문에서 완전히 빠져 나와서else 절 .

그러나 실제로 내 정신 매핑은 단순히 패턴 C / C ++ 패턴의 '구조화 된'버전이라는 것입니다.

  for (...) {
    ...
    if (test) { goto done; }
    ...
  }
  ...
done:
  ...

따라서 직접for...else 이해하지 않고 직접 만지 거나 직접 쓰면 패턴에 대한 위의 이해로 정신적으로 번역 한 다음 파이썬 구문의 어느 부분이 패턴의 어느 부분에 매핑되는지 알아냅니다.

(코드가 구조화되어 있는지 아니면 구조화되어 있지 않은지가 아니라 특정 구조에 전용 키워드와 문법이 있는지 여부 만 차이가 있기 때문에 '구조화'를 따옴표로 묶었습니다)


1
어디 else입니까? done:레이블이 프록시 또는를 의미 else:한다고 생각하면 정확히 거꾸로 가지고 있다고 생각합니다.
Alexis

'다른'코드를 입력 것 '...'@alexis 직전done: 레이블입니다. 전반적인 대응은 아마도 가장 잘 말했을 것입니다 : 파이썬에는 else-on-loop 구조 가 있어서이 제어 흐름 패턴을없이 표현할 수 있습니다 goto.
zwol

이 제어 흐름 패턴을 실행하는 다른 방법 (예 : 플래그 설정)이 있습니다. 그것이 else회피하는 것입니다.
Alexis

2

else와 페어링하면 for혼동 될 수 있습니다. 키워드 else가이 구문에 적합한 선택 이라고 생각하지 않지만 , contains else과 (와) 페어링 하면 실제로 의미 if가 있음 break을 알 수 있습니다. else앞의 if설명 이 없으면 구문 디자이너가 키워드를 선택한 이유가 믿기지 않습니다 .

그것을 인간의 언어로 보여 드리겠습니다.

for용의자 그룹의 각 사람 if은 형사 break수사입니다. else보고서 실패.


1

내가 생각하는 방식의 핵심은의 의미를 고려하는 continueelse입니다.

언급 한 다른 키워드는 루프에서 벗어나고 (정상적으로 종료 continue되지는 않지만 ) 루프 내에서 나머지 코드 블록을 건너 뜁니다. 루프 종료보다 우선 할 수 있다는 사실은 부수적입니다. 실제로는 루프 조건식을 평가하여 정상적인 방식으로 종료됩니다.

그런 다음 else절은 정상적인 루프 종료 후에 실행 된다는 것을 기억하면 됩니다.


0
# tested in Python 3.6.4
def buy_fruit(fruits):
    '''I translate the 'else' below into 'if no break' from for loop '''
    for fruit in fruits:
        if 'rotten' in fruit:
            print(f'do not want to buy {fruit}')
            break
    else:  #if no break
        print(f'ready to buy {fruits}')


if __name__ == '__main__':
    a_bag_of_apples = ['golden delicious', 'honeycrisp', 'rotten mcintosh']
    b_bag_of_apples = ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
    buy_fruit(a_bag_of_apples)
    buy_fruit(b_bag_of_apples)

'''
do not want to buy rotten mcintosh
ready to buy ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
'''
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.