티스토리 뷰

반응형

[※ 주의 ※] 아래를 이해하지 않고 이 글을 볼 경우, 이해가 되지 않는 부분이 있을 수 있습니다.

 

1. [Python] if-else 뿐만 아니라 for-else / while-else도 가능하다고?

 

★ 본 글은 CPython core developr인 Nick Coghlan의 글 http://python-notes.curiousefficiency.org/en/latest/python_concepts/break_else.html)을 바탕으로 작성되었습니다! ★


파이썬에는 else문과 관련하여 재밌는 사실들도 많고, 파이썬 만의 독창적인 문법을 가지는 경우도 많다.

 

그러나, for-else / while-else문을 소개하는 글에서 이야기했듯이, else문은 많은 프로그래머들을 혼란에 빠뜨리기 충분하다.

 

이번 포스팅은 else문에 대한 혼란을 줄이고, 왜 아직 이렇게 사용하는지에 대하여 설명한다. 끝까지 인내심을 갖고 읽어주길!

thumbnail
else에 대하여 깊게 알아보자.

 


왜 else문은 어려울까

다음 예시를 보자. else문과 관련된 두 코드의 실행 결과를 마음속으로 생각해보자.

 

1
2
3
4
5
6
7
8
9
10
# -*- coding: utf-8 -*-
for x in [1]:
    print("Not else")
else:
    print("Else")
# --------------------
if [1]:
    print("Not else")
else:
    print("else")
cs

 

생각해 보았는가? 출력 결과를 나타내면 다음과 같다.

 

1
2
3
4
Not else
Else
# --------------
Not else
cs

 

if <iterable> 문으로 이루어진 제어문과, for <variable> in <iterable>로 이루어진 제어문은 매우 비슷해 보인다. 따라서, 두 코드도 비슷한 역할을 할 것이고 실행 결과도 같을 것이라 생각할 수 있다.

 

이러한 전제는 잘못되었다. 첫 번째 코드의 경우 for문 내의 print와 else문 내의 print 모두 실행되고, 두 번째 코드의 경우, if문 내의 print만 실행되었다.

 

단순히 <iterable>이 비어있지 않다고 else를 무시해버리면 잘못된 예측인 것이다.

 

그럼, 다음 코드의 실행 결과는 무엇일까? 한번 다시 생각해보자.

 

1
2
3
4
5
6
7
# -*- coding: utf-8 -*-
= [1]
while x:
    print("Not else")
    x.pop()
else:
    print("Else")
cs

 

x.pop() x는 빈 list가 되는데, 과연 else는 실행이 될까? 이에 대한 출력 결과는 다음과 같다.

 

1
2
Not else
Else
cs

 

설령 못 맞췄어도 너무 실망하지 말자. else문에 대한 탐구를 해 볼 기회가 없었기 때문이다.

 

위 코드에선 <iterable>이 빌 때까지 while문이 작동되고, 이후에 else문이 실행된다는 것을 확인할 수 있다.


else도 다 같은 else가 아니다!

그럼, 어떤 것이 실행 결과의 차이를 만드는가? 두 if-else와 for-else에서의 코드는 유사해 보여도, 이러한 유사성 때문에 else에 대한 혼란을 가중시킨다.

 

사실, if-else에서 사용되는 else의 용도와, for-else / while-else 등 제어문에서의 사용되는 else는 다른 용도를 지니고 있다고 해도 무방하다.

 

전자의 경우, else는 조건 표현식(conditional expression) 과 대응되는 개념이고, 후자의 경우 else는 완성 표현식(completion expression)과 대응되는 개념이다.

 

조건 표현식은 우리가 아는 boolean 변수 True / False 에 따라 분기가 결정되는 개념이고, 완성 표현식은 하나의 코드 덩어리가 완전히 실행되면 실행되는 개념이다.

 

따라서, 우리가 익숙한 꼴로 정리하면 다음과 같이 정리할 수 있다.

 

1
2
3
4
5
6
7
# -*- coding: utf-8 -*-
for x in <iterable>:
    do_something()
except break: # break가 실행되면
    pass # else를 건너뜀
else:
    do_something_if_fully_executed() # 만약 break를 마주치지 않았다면 실행
cs

이러한 else는 언제 사용 가능할까?

완성 표현식의 개념에서 사용되는 else는 보통 조건에 맞는 검색을 할 때 유용하게 사용할 수 있다.

이에 대한 구체적인 설명은 for-else / while-else 포스팅에서 찾을 수 있다.


하지만 loop이 실행되지 않아도 else문은 실행되잖아요!

좋은 지적이다. 이럴 경우 미리 <iterable>이 비어있는지를 확인하거나, 적절한 예외 처리를 해주어야 한다.

다음과 같이 작성할 수 있다.

 

1
2
3
4
5
6
# -*- coding: utf-8 -*-
= None
for x in some_list:
    do_something(x) # x에 대한 여러 연산 수행
if x is None# 만약 비어있을 경우...
    raise ValueError("some_list is empty!"# 예외 실행
cs

 

만약, None이 필요한 경우, 빈 class의 비어있는 객체를 대신하여 활용할 수 있다.

 

1
2
3
4
5
6
# -*- coding: utf-8 -*-
= _empty = object()
for x in some_list:
    do_something(x) # x에 대한 여러 연산 수행
if x is _empty: # 만약 비어있을 경우...
    raise ValueError("some_list is empty!"# 예외 실행
cs

else문을 더 응용하여 보자.

else문을 더 활용하여 보면, try-except 예외처리에서도 활용 가능하지 않을까?

 

만약 try문에서 예외가 발생하였으면 except의 코드 덩어리가 실행되는 것과 반대로, try가 완전히 실행되었으면 특정 코드 덩어리가 실행되게 할 수 없을까?

 

이러한 요구에 알맞은 것이 완성 표현식 개념의 else문이다.

 

이를 정리하면 다음과 같이 작성할 수 있다.

 

1
2
3
4
5
6
7
# -*- coding: utf-8 -*-
try:
    do_something() # 예외가 발생할 수 있는 코드
except# 예외 발생시...
    handling_error() # 예외 처리
else# 예외가 발생하지 않을 시...
    do_something_if_fully_executed() # 실행
cs

너무 헷갈립니다! else문 대신 다른 걸 사용하면 안 될까요...?

많은 파이썬 코어 프로그래머들은 이 문제에 대하여 치열하게 토론해왔다. 이에 대하여 여러 제안들이 올라왔었다.

 

1. 두 번째 의미의 'else'문을 그래도 나둬야 한다!

2. 'else'라는 것이 뜻에 맞지 않고 헷갈리므로, 다른 표현으로 대체되어야 한다!

3. 'else'라는 것이 유용하긴 하나, 'break'가 없으면 대부분 쓸모없으므로, 이 경우 에러나 경고를 발생시키자!

4. 'else'문이 직관적으로 알아보기 힘드므로, 'else' 문이 for-loop이 거짓일 경우 실행되도록 수정하자!

5. 'else'문 자체가 쓸모가 별로 없으므로, 그냥 이러한 syntax는 제거하자!

6. 'else'문이 for-loop가 제대로 실행되었을 때 실행되는 syntax라면, for-loop이 제대로 실행되지 않았을 경우에 대한 새로운 syntax가 필요하다!

 

최종적으로 1번 제안이 채택되었는데 하나하나씩 따져보자. 왜 1번이 되었을까?


1. 두 번째 의미의 'else'문을 그래도 나둬야 한다!

프로그래밍 언어가 최대한 이해하기 작성되어야 한다는 것은 맞지만, 이 특징이 프로그래밍 언어가 항상 "직관적"이어야 한다는 의미는 아니다.

 

파이썬의 대원칙 Zen of Python에 의하면, "네가 네덜란드가 아닌 이상, 원래 처음부터 뻔한(쉬운) 방법은 없다!"인 구절이 있다. 결국 else문도 쓰다 보면 익숙해진다는 의미를 함축하고 있다.

 

비록 파이썬 언어체계는 발전이 있어야 하지만, 아직 파이썬 개발자들에게 'else'문을 대체할만한 "완벽한" 표현과 이유를 찾지 못하였다.

 

결국 코드를 작성하는 스타일은 본인 자신이 결정할 수 있고, break 없는 for-else도 이상해 보이지만 이것도 하나의 스타일로 인정해야 한다는 것이 이 제안의 주요 주장이었다.


2. 'else'라는 것이 뜻에 맞지 않고 헷갈리므로, 다른 표현으로 대체되어야 한다!

 

몇몇 코어 개발자들이 이에 대한 주장 하였다.

 

사실 'else'문에서 혼란이 발생하는 이유는, 'else'의 두 개념 사이에 뭔가 큰 연관성이 없어 보이기 때문이다. 따라서 'else'의 완성형 표현의 의미로 사용될 경우, 다른 표현으로 대체하자는 것이다.

 

하나의 제안으로, 완성형 표현의 경우 'else'를 버리고, 다른 문구 혹은 단어로 대체하는 것이다. 다음과 같이 말이다. 

for item in <iterable>:
	do_something(item)
else no break:
	process()

이 경우 'else' 대신 "no break"라는 문구로 대체되었다. 이러할 경우 for문 이후에 어떤 일이 발생하는지 직관적으로 알아보기 쉽다는 장점이 있다.

 

실제로 'else' 대신 "no break"을 도입하자는 제안도 올라왔었다. 하지만, 다음과 같은 단점들로 인하여 기각되었다.

 

- 한 단어 대신 세 단어가 필요하다. 코드가 쓸데없이 길어진다.

- 기억하기 쉽지 않다.

=> "else no break" 인지, "elif no breaks"인지, "if no break" 인지, "else not break" 등등 잘못된 syntax를 사용할 가짓수가 너무나도 많다.

- "break"를 하나의 전역 변수로 착각할 만한 요소가 있고, 사용자가 loop 밖에서 break를 사용할 가능성이 있다.

- 사실 python 내부에서는 실제 test가 진행되지 않는다.

=> 실제 코드를 컴파일할 시 no break인지 break인지 판단하지 않는다는 의미이다.

 

두 번째 제안으로, 'else' 대신 'then'이라는 단어를 활용하자는 제안이 올라왔다.

 

이 경우 한 단어이고, 제어문으로서 설명해주는 단어라는 장점이 있다. 하지만, 'then' 이란 단어 자체가 하나의 동사나 명사가 아니므로, 실제 자주 사용될 문법이 아닐 가능성이 크다.

 

세 번째 제안으로, 'else' 대신 'finally'이라는 단어를 활용하자는 제안이 올라왔다.

 

이 경우 사용자들이 try... except... finally 예외 처리 구문과 같이 작동할 것이라고 생각할 수 있기에 많은 동의를 얻지 못하였다.


3. 'else'라는 것이 유용하긴 하나, 'break'가 없으면 대부분 쓸모없으므로, 이 경우 에러나 경고를 발생시키자!

실제로 많은 코어 개발자가 이 제안에 뜨겁게 토론하였다.

 

만약 'break'가 for나 while문에 포함되어 있지 않으면, 파이썬 컴파일러 자체에서 경고나 에러를 띄우거나, 외부 소프트웨어 (ex. PyChecker, PyLint)에서 이를 검사할 수 있도록 해야 한다는 주장이다.

 

이에 대하여 3가지 세부 제안들이 올라왔다. 각 제안들의 찬성 근거들과 반대 근거들을 알아보자.

 

3-a) break 없는 for-else문은 잘못되었으므로, SyntaxError를 띄워야 한다!

찬성:

  • 많은 사람들이 합리적이라고 생각하는 관례로 파이썬 컴파일러가 작동한다.

반대:

  • 아직 관례가 매우 적다.
  • 현재 break가 없는 for-else문으로 작성된 코드가 존재하므로, 너무 급진적인 변화는 자제해야 한다. 먼저 deprecation을 한 다음 진행해도 늦지 않다.
  • break가 없는 for-else 문이 사용자가 의도한 대로 작동한다면, 이를 에러라고 파이썬 사용자를 설득하기에는 어렵거나 거의 불가능하다. 
  • 컴파일하였을 때, 컴파일러가 자동으로 break가 필요 없을 경우 삭제하도록 최적화하는 방향으로 진행하면 된다.
  • 에러를 피하기 위하여 파이썬 사용자들이 필요 없는 break문을 사용하여야 한다.
  • for-else에서 break가 없다는 것이 에러의 원인이라는 증거는 거의 없다.

 

3-b) break가 없는 for-else문은 무의미하므로, 이에 대하여 컴파일러가 경고를 띄워야 한다!

찬성:

  • 'else' 부분은 에러가 자주 발생하는 부분이다. 예를 들어, 제어문 안에서의 'if-else'에서 들여 쓰기 오류로 인하여 else가 for문과 대응되는 경우 에러가 발생할 수 있다. 이러한 경우를 사전에 방지할 수 있다.
  • 몇몇 파이썬 사용자들은 'else' 부분이 언제 실행되는지 경고를 통해 알 수 있고, 혼란을 방지할 수 있다.
  • 다른 프로그래밍 언어에서도 이와 같은 경우 경고를 띄우는 사례들이 있다.
  • 파이썬의 경우 아직 이런 경우와 관련된 선례가 적지만, 다른 경고들과 같이 경고들을 띄워 하나의 선례로 남겨야 한다.

반대:

  • 파이썬 컴파일러는 가벼워야 하고, 따라서 코드 규칙에 관한 경고는 거의 표시하지 않는다. 굳이 존재하는 코드 작성 요령에 대하여 경고를 띄울 필요는 없다.
  • break가 없는 for-else 문이 사용자가 의도한 대로 작동한다면, 이를 경고라고 사용자를 설득하기에는 어렵거나 거의 불가능하다.
  • 파이썬 컴파일러는 파이썬 사용자가 어떤 의도로 작성하는지 "예상"하여서는 안된다. 그저 파이썬 작성 규칙에만 맞는지 확인하면 된다.
  • 이러한 경고는 컴파일러를 복잡하게 하며, for-else와 while-else가 자주 쓰이는 구문이 아닌 만큼 경고를 띄울만한 가치가 있는지 모르겠다.
  • 너무 많은 경고는 비숙련된 파이썬 사용자들에게 부주의를, 숙련된 파이썬 사용자들에게 귀찮음을 불러일으킬 수 있다.

 

3-c) 'break'가 없는 for-else문은 흔하지 않으므로, 외부 서드 파티 소프트웨어 (ex. PyChecker, Pylint)에서 경고를 띄울 수 있도록 하자!

찬성:

  • 충분히 합리적인 의견이다. 필요한 경우 위 도구들을 활용하면 되고, 만약 불필요하다 생각하면 활용하지 않으면 된다.
  • 'else'의 잘못된 사용으로 인한 에러는 굉장히 사소하므로, 이러한 에러 해결에는 많은 노력이 들어가지 않을 것이다.

반대:

  • 외부 서드 파티 소프트웨어는 표준 라이브러리에 포함되어 있지 않고, 에러 해결에 적은 노력이 들어갈지는 모른다.

결론적으로, 세 제안 모두 기각되었다.


4. 'else'문이 직관적으로 알아보기 힘드므로, 'else' 문이 for-loop이 거짓일 경우 실행되도록 수정하자!

파이썬 사용자들이 'else'에 익숙하지 않아 언제, 어떻게 실행될지 모르므로, 직관적으로 코드를 읽기 쉽게 하기 위하여 for-loop이 거짓일 경우 실행되도록 바꾸자는 제안이다.

 

하지만, 이러한 급진적인 변화는 이미 작성된 코드의 실행 방법을 변경할 것이고, 먼저 deprecation이 진행된 다음, 충분한 토론을 거치고 바꾸어도 늦지 않다는 것이 주류 의견이었다.

 

그리고, 이 제안은 큰 공감을 얻지 못하였다. (Python 4000 버전에나 이식될 수 있다는 농담이 돌았다.)

 

5. 'else'문 자체가 쓸모가 별로 없으므로, 그냥 이러한 syntax는 제거하자!

위 4번과 같은 이유로 큰 공감을 얻지 못하였다.

 

6. 'else'문이 for-loop가 제대로 실행되었을 때 실행되는 syntax라면, for-loop이 제대로 실행되지 않았을 경우에 대한 새로운 syntax가 필요하다!

만약 for-loop가 제대로 실행되지 않았다는 것을 검사하고 싶을 경우, 추가적인 if-else를 활용하면 문제 되지 않는 부분이다.

if some_list:
    for item in some_list:
       do_something(item)
else:
    print("Empty")

위와 같이 아주 간단히 확인할 수 있기 때문에, 굳이 새로운 syntax를 만들어야 하는 이유가 없었다.


결론적으로 1번 제안이 채택되었고, 이후에 정말, 정말 'else'에 대한 변경이 필요할 경우 향후 제안에서 다룰 수 있도록 하는 방향으로 결정되었다.


결론

else문의 색다른 활용(완성형 표현)은 제어문 활용에 더 많은 자유도를 부여하지만, else문 자체가 새로운 문법적인 통찰이나 코딩 스타일에는 큰 변화를 주진 못한다. 따라서, else문에 대한 고찰은 여기까지만 하고, 파이썬의 다른 부분에 더 집중하자!

 

도움이 되었다면 지나가는 길에 하트 하나 눌러주세요, 양질의 글을 쓰는데 하나의 동기부여가 됩니다😍

지적이나 오타 수정 댓글 환영합니다!!

 

 

반응형
댓글
Total
Today
Yesterday
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함