파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

* 파이썬의 12번째 주제인 "리스트 데이터 구조"를 먼저 보고 오시기 바랍니다.

우리가 파이썬의 8번째 주제인 [콘트롤 구조]에서 모든 명령어는 "반드시" 수행되고 "한번만" 수행되게 되어 있음을 살펴봤고, 9번째 주제인 [분기를 위한 if, elif, else]에서 "반드시"라는 제약사항을 조정할 수 있음을 살펴보았다. 이번 글에서는 "한번만"이라는 제약사항을 조정하여 명령문을 "여러번 반복해서" 실행할 수 있도록 하는 키워드인 for와 while에 대해 살펴보도록 하겠다. 

for 키워드를 이용해서 만들어서 반복을 일반적으로 for 루프(loop)라고 부른다.

○ for each 반복문

반복을 나타내는 키워드는 거의 모든 프로그래밍 언어에서 for 라는 키워드를 사용한다. 그래서, 일반적으로 for 가 사용된 반복문을 "for 문"이라고 부른다. 파이썬도 for를 사용해서 반복을 나타낸다. 파이썬의 for 문을 "for each 문" 이라고 부르기도 하는데 다음에서 그 이유를 살펴보자.

파이썬의 for 문의 기본적인 형태를 보면 아래와 같다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

실행되는 문장은 print(x)라는 문장이다. 우리말로 "x 값을 출력하라" 이다. 문장은 1개인데 아래의 실행결과를 보면, 실제로는 5번 반복 수행되었음을 알 수 있다. 이렇게, 어떤 문장(들)을 여러번 반복하여 실행되게 만들 수가 있는데, 이런 형태의 컨트롤 구조를 반복 (repetition, loop)이라고 부른다. 

for 루프의 기본적인 구성은 아래와 같다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

for 키워드 뒤에 변수(iterator)가 하나 오고, in 키워드가 오고, 그 뒤에 시퀀스(sequence) 타입의 데이터 구조가 온다. 시퀀스 타입의 데이터 구조는 우리가 살펴봤던 리스트, 튜플과 같이 여러 데이터가 순서대로 연결되어 있는 형태를 가지는 데이터 구조를 나타낸다. 문자열도 시퀀스 타입이다.

예제로 사용된 for x in [1, 2, 3, 4, 5] 문의 실행 순서를 한번 살펴 보자.

for 문의 콜론( : ) 뒤에 묶여져 있는 명령어들이 반복이 되는데, 가장 첫번째 반복은 x 값이 리스트의 첫번째 요소인 1일 때 이루어진다. 즉 x 값이 1로 assign 된 상태에서 반복이 이루어진다. for 문에 묶여져 있는 명령어들이 모두 실행이 되면 그 다음 반복이 이루어진다. 이 때는 iterator인 x 변수의 값이 리스트의 다음 요소인 2가 된다. 즉 x 값이 2인 상태로 한번의 반복이 더 이루어진다. 이러한 과정이 계속되어, x 값이 3일 때 반복이 이루어지고, x 값이 4일 때 반복이 이루어지고, x 값이 5일 때 반복이 이루어진다. 5가 마지막 값이므로, 5번째 반복이 완료된 후에 for문의 실행은 끝나게 된다.  

이 형태를 가만히 보면 "리스트에 포함되어 있는 각 (each) 요소에 대하여 콜론( : ) 이하를 반복하여 실행한다" 가 된다. 이런 형태의 반복문을 특별히 for each 문이라고 부른다. for 는 "대하여" each 는 "각각에". 합쳐서 for each는 "각각의 ...에 대하여" 이다.

이런 의미에서 다음과 같은 반복문을 생각해 보자.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

리스트에 포함되어 있는 "각 악기이름에 대하여" I like to play the ( 악기명 ) 을 출력하는 명령어이다. 첫번째 반복에서는 x 값이 'piano' 이다. 첫번째 반복에서 x 값을 출력해 보면 당연히 'piano' 라는 문자열이 보일 것이다. 두번째 반복에서는 x 값이 'guitar'로 바뀐다. 두번째 반복에서 x 값을 출력해 보면, 너무도 당연히 'guitar' 라는 문자열 값이 보일 것이다. 요소의 수가 3개이기 때문에 세번의 반복이 이루어진다. 마지막인 세번째의 반복에서는 'violin'이 x 값이 된다.

x='piano' 로 첫번째 반복이 실행되고, 그 다음으로 x='guitar'로 두번째 반복이 실행되고, 마지막으로 x='violin' 이 되어 세번째 반복이 이루어 진다. 즉, 리스트를 구성하는 각 요소에 대하여 1회씩의 반복이 만들어진다. 

○ 반복을 센다? 카운트 하는 반복문.

반복문을 만들 때 2가지를 고려해야 한다. 첫째는 몇번 반복할 것인가? 두번째는 각 반복을 무엇이라고 가리킬 것인가? 이다. 말이 조금 애매한데, 우리가 흔히 구슬을 반복해서 셀 때 이런 표현을 사용한다.

한개씩 세면서, 하나, 둘, 셋, 넷, 다섯.

두개씩 묶어서 세면서, 둘, 넷, 여섯, 여덟, 열.

다섯개씩 묶어서 세면서, 오, 십, 십오, 이십, 이십오.

열개씩 묶어서 세면서, 십, 이십, 삼십, 사십, 오십.

모두 몇 번을 (반복해서) 세었나? 모두 5번씩 (반복해서) 세었다. 각 반복을 나타내는 iterator 변수를 x 라고 한다면...

첫번째 경우는 5번의 반복을 x가 하나(1)일때 한번, x가 둘(2)일때 한번, x가 셋(3)일때 한번, x가 넷(4)일 때 한번, x가 다섯(5)일때 한번. 그래서 총 5번의 반복.

두번째 경우는 x=2, x=4, x=6, x=8, x=10 일때 각각 반복. 그래서 총 5번의 반복

세번째 경우는 x=5, x=10, x=15, x=20, x=25 로서 반복. 역시 총 5번의 반복

마지막 경우는 x=10, x=20, x=30, x=40, x=50 으로서 반복. 역시 총 5번의 반복

똑 같이 5번의 반복이 이루어졌다. 단지 각 반복을 나타내는 iterator 값이 다를 뿐이다. 

이렇듯이 반복을 카운트(count) 하는 형태의 반복이 있다. 위에서 봤던 for each 문이 시퀀스를 구성하는 "각 요소에 대하여" 라는 의미가 강했다면, 이런 형태의 반복은 "몇 번째" 라는 의미가 강한 형태의 반복이다. 물론, 형태는 다르지 않다. 단지, 코딩하는 사용자가 부여하는 의미에서 차이가 있다는 뜻이다. 다시 원래의 샘플 코드를 보자.  

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

무엇으로 읽히는가? 

첫째 경우로서, 리스트를 구성하는 각 요소인 1, 2, 3, 4, 5 에 대해서... 라고 읽을 수도 있고
두번째 경우로서, x=1일때, x=2일때, x=3일때, x=4일때, x=5일때 반복해서 총 5번의 반복을 한다... 라고 읽을 수도 있다.

for 키워드를 사용해서 특정한 회수만큼 반복하게 만들어 보자.

만약, 5번 반복하는데 그 횟수를 1, 2, 3, 4, 5로 세고자 한다면 for 루프의 구조는 아래와 같다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

똑같이 5번을 반복하는데, 그 횟수를 2, 4, 6, 8, 10 으로 세고자 한다면 for 루프의 구조는 아래와 같다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

역시 똑같이 5번을 반복하는데, 그 횟수를 10, 20, 30, 40, 50 으로 세고자 한다면, for 루프의 구조는 아래와 같다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

만약에 1, 2, 3, 으로 시작해서 100번을 반복하는 for 문을 만들고자 한다면, for 루프는 어떻게 만들어야 할까? 설마?

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

이러한 문제는 파이썬에서 제공하는 range( ) 함수를 이용해서 해결할 수 있다.

○ range( ) 함수

range( ) 함수의 설명을 보면 다음과 같다. (# 참고로, 주티터 노트북에서 어떤 이름 뒤에 물음표(?)를 붙이면 그 이름에 대한 설명이 팝업된다. "range 라는 이름이 뭐지?" 라는 의미에서 range? 라고 쓰면 된다) 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

range( ) 함수는 start, stop, step 등 3개의 인자(argument)를 갖는다. 

기본적으로, start 부터 시작해서 stop에는 미치지 못하게, step 만큼 증가(또는 감소)한다 (stop 은 포함하지 않음에 주의). 아래의 range(0, 5, 1) 은 "0부터 시작해서 1씩 증가하되 5보다는 작게" 라는 뜻이다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

만약에 "2부터 시작해서 2씩 증가하는데 10보다는 작게"를 나타내는 range( ) 함수의 형태는 어떻게 될까?

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

위 문제에서 10을 포함하고 싶다면 range( ) 함수의 인자는 어떻게 조정되어야 할까?

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

range( ) 함수에서 start나 step 값은 생략할 수 있다. start를 생략하면 디폴트 값으로 0이 사용되고, step 값을 생략하면 디폴트 값으로 1이 사용된다. 단, start 값 만을 생략하는 경우는 불가능하다. 그래서 아래의 경우만 가능하다

range(start, stop, step)    : 기본적인 형태
range(start, stop)           : step 값이 생략된 형태, step은 디폴트로 1
range(stop)                  : start와 step이 생략된 형태, start의 디폴트는 0, step의 디폴트는 1

두번째 경우와 세번째 경우의 예제는 아래에서 확인하기 바란다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog
파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

step 값을 음수로 하면 카운트 다운 (count down) 도 당연히 가능하다. 예제를 본다면,

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

○ For 와 List

For 문으로 만들어진 반복과 리스트 데이터 구조는 너무나 잘 어울리는 조합이다. 예를 들어 5개 요소를 가진 리스트의 값들을 화면에 출력하는 프로그램을 만들어 보자.

우선, 리스트의 각 요소에 대하여 (for each) 값을 출력하는 것이다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

또 하나의 방법으로 각 요소의 인덱스를 이용해서 접근하는 방법이 있다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

반복이 보이는가? 인덱스 값이 k가 0, 1, 2, 3, 4 로 변함에 따라 print(a[k]) 가 반복되는 형태로 볼 수 있다. 이를 for 문을 바꾸어 보면 아래와 같다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

다시 얘기하지만, for 반복문과 리스트의 조합은 매우 효과적으로 활용되는 형태이다. 잘 이해해 두어야 한다. 나중에 다룰 [알고리즘 연습] 포스트에서 좀 더 구체적으로 다루어 보자.

○ continue와 break

continue와 break를 활용해서, 반복을 좀 더 fine(세밀?) 하게 통제할 수 있다.  기본적인 동작은 아래의 그림에 나타낸 바와 같이, 반복문 내에서 break 명령어가 실행되면, 전체 루프가 종료가 되는데 비해, 반복문 내에서 continue 명령어가 실행되면, 혹시 남아있는 명령어가 있더라도 무시하고 다음 번 반복으로 넘어간다.  

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

for 루프 안에서 break 명령어가 실행되면, break를 포함하고 있는 for 루프를 완전히 빠져 나오게 된다. 그래서 break 명령어는 혼자 사용되는 경우는 없고, 항상 if 문과 함께 사용된다. break와 연결된 if 의 조건문이 True가 되면 break가 실행되어 전체 반복이 종료하게 된다.

아래의 예제는 0 부터 100까지 카운트를 하는 중에, iterator 변수 값 (x 값)이 사용자가 입력한 값 (a값) 보다 크면 break 가 실행되어 for 루프를 종료하게 되는 코드이다. for 루프의 iterator 변수인 x 값은 0부터 1씩 증가한다. 만약에 a 값이 6이라면 x 값이 6보다 작거나 같은 동안은 (즉, x 값이 0, 1, 2, 3, 4, 5, 6 인 동안) #3의 조건식이 False 가 되어 break 가 실행되지 않는다. 그래서 #5 명령어인 print(x)가 실행되어 화면에 출력이 된다. 그런데 x 값이 7이 되면, #3의 조건식이 참이 되면서(7>6), break 가 실행된다. break 가 실행되면 그 문장을 포함하고 있는 for 루프 (#2에서 #5 까지)를 완전히 빠져나와서 #6 명령어가 실행되게 된다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

사족으로, break를 설명하면서 "~하는 동안" 이란 표현을 사용했었는데, while이 반복을 만드는 또다른 키워드인 이유가 되겠다. 아래에서 while 문을 공부할 때 다시 살펴보자.

다음으로 continue를 살펴보자. for 루프에서 continue가 실행되면, (continue 문장 다음에 있는 명령어들은 무시하고) 그 다음 반복으로 넘어가게 된다. 예를 들어 보자. 아래의 코드는 iterator(반복 변수) x 값이 0, 1, ..., 10으로 10번 반복이 되는 for 루프이다. 현재 x 값이 2라고 하자. 그러면, #2에서 조건식이 True 가 되면서 continue가 실행된다. continue 명령어가 실행되면 for 루프 내의 나머지 명령어 (예제 코드에서는 #4)는 생략하고 다음번 반복으로 넘어간다. 실제로, 출력 결과에 2 값이 없음을 확인해 보기 바란다. 여기서, 다음번 반복은 반복변수(iterator) x 값이 3이 되는 반복이다. 참고로, #2에서 조건식 x%2 == 0 은 어떤 값 x를 2로 나누었을 때 나머지(x%2) 값이 0이면, 즉, 짝수이면 True 가 된다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

○ while 루프

다음으로 while 키워드를 이용한 반복에 대해 살펴보기로 하자.  For를 사용해야 하는 경우가 따로 있고 while을 사용해야 하는 경우가 따로 있는 것이 아니다. For로 만들 수 있는 반복은 while 로도 만들 수 있고, 그 반대도 역시 참이다. While 이라는 단어의 뜻에서 유추할 수 있듯이, 특별히 "~하는 동안" 또는 "~하지 않는 동안" 이 반복의 구성 형태가 되는 경우에 for 보다는 while이 유리하다. 

루프를 만들어야 겠는데, "~하는(하지 않는) 동안"이 머리속에 떠오르면 while 을 사용해 보자. 예를 한번 살펴보자.

키보드로 부터 데이터를 계속 입력 받는데, 입력받는 값이 양수인 동안
파일로 부터 데이터를 읽어 들이는데, 파일의 끝에 도달하지는 않은 동안
10번을 반복해야 하는데, 반복수가 10번 보다는 적은 동안

While 루프의 형태는 다음과 같다. 키워드는 while 이고 바로 뒤에 "~하는 동안"에 해당하는 조건문이 위치한다. 그리고 콜론( : )이 위치한다. 실제로 조건문이 True 인 동안은 계속 반복하게 된다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

위의 while 루프에서 반복의 조건문은 a<10 이다. 그런데, 이 조건문은 a 값이 무엇이냐에 따라 True 이 되기도 하고 False 가 되기도 한다. 만약에 조건문에 변수가 사용되면, while 루프에 들어가기 전에 그 변수의 값이 결정되어야 조건문의 참/거짓을 결정할 수 있게 된다. 

따라서 실제로는 아래와 같은 형태가 된다. #2의 조건식 연산에 필요한 a 값이 #1에서 할당되었다. a 값이 5이므로 while 의 조건문은 True 이 되어 while의 콜론( : )에 묶여 있는 문장(들)이 1회 실행된다. 우리의 예제에서는 print(a) 가 실행되어 화면에 5라는 값이 출력된다. 모든 명령어가 수행 완료되면 다시 while 의 조건식을 연산한다. a 값은 여전히 5 이므로 True 가 되고 print(a)가 1회 반복된다. 화면에 5 값이 출력되고 다시 while 의 조건식을 연산한다. 만약 조건식이 False 가 되면 while 루프를 빠져나오게 된다. 그런데, 우리 예제는 a 값이 변하지 않으므로 항상 True이 되어 끝없이 반복이 이루어지는 형태가 된다. 이런 형태를 무한 루프(infinite loop) 라고 부른다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

주피터 노트북에서는 무한루프가 발생하면 해당 셀의 In[ ] 에 일련번호가 나타나지 않고, 다음 그림과 같이 * 표가 나타나게 된다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

그럴 때는 중간에 강제로 정지하는 것이 필요한데, 이를 인터럽트(interrupt)라고 부른다. 소위, 코드가 진행 중인데 방해(인터럽트)하여 강제로 중단시키는 것이다.  주피터 상단의 툴바(tool bar)에서 ■ (interrupt the kernel) 버튼을 누르면 된다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

경우에 따라서는 ■ 버튼으로 실행이 종료되지 않는 경우가 있다. 이 경우에는, Kernel 메뉴에서 Restart & Clear Output 메뉴를 실행하도록 하자. 커널이란 용어가 낯설텐데, 일단, 커널(Kernel)은 우리가 입력한 파이썬 명령어를 실행시켜주는 파이썬 명령어 해석기(interpreter) 정도로 파악하고 넘어가자.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

자, 다시 원래의 코드로 돌아가 보자. 여러분들이 보기 쉽도록, 위의 코드를 다시 복사해서 가져왔다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

루프가 반복됨에 따라, 조건문을 구성하는 변수의 값이 바뀌지 않는다면, 한번 True 면 영원한 True로 무한반복이 되거나, 한번 False 이면 영원히 False가 되어 전혀 반복이 되지 않는 구문이 된다. 후자의 경우에는 전혀 의미가 없고,  전자의 경우인 무한반복은 특별히 의미있는 경우도 있다. 예를 들어, 사용자로 부터의 계속되는 요청(request)에 무한히 반응(response) 하는 웹서버 프로그램 같은 경우 말이다. 그런 특별한 경우를 제외하고, 우리가 다루는 보통의 프로그램에서 무한반복되어야 하는 경우는 없다고 보면 된다. 

그래서, 보통은 조건식에 포함된 변수가 while 루프 안에서 변하게 된다. 예를 들면 위의 코드를 아래와 같이 바꿀 수 있을 것이다.

[문제1] 처음에 셋팅된 a 값이 루프가 반복될 때 마다 1씩 증가하는데, 그 값이 10 미만인 동안 반복이 이루어진다
[문제2] 루프가 반복되면서 사용자로 부터 a 값을 새로 입력받는다. 입력받은 a 값이 10 미만인 동안 반복이 이루어진다

위의 [문제1]에 해당하는 코드를 만들어 보면 아래와 같다.

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

위의 [문제2]에 해당하는 코드를 보이면 아래와 같다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

○ do~while 루프

위에서 while 루프를 살펴보았다. While 루프는 루프에 들어가기 전에 "반복을 시작할 지"에 대한 조건식을 체크한다. 혹시, 루프를 나갈 때에 "반복을 그만두고 나갈지"에 대해 체크하는 형태는 없을까? 실제로 그런 형태를 거의 모든 컴퓨터 언어들이 do~while 이라는 구문형태로 가지고 있다. 하지만, 파이썬은 불필요하다는 이유로 제공하고 있지 않다. 실제로 아래와 같은 형태로 do~while 을 모의할 수 있다. 

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog

○ a=a+1

간혹 어려움을 겪는 코드 중에 하나가 a=a+1이다. 사실은 어렵지 않은 코드인데, 몇몇 학생들이 간혹 오해하는 경우가 있어 사족이겠지만 설명을 추가하고자 한다. 일단 "a=" 이라는 부분은 "a에다 저장해라" 또는 "a가 가리켜라"로 해석하면 된다. 그럼, 뭘 저장하고, 뭘 가리키라는 말인가? "a+1" 값을 저장하라는 뜻이다. a+1 값은 어떻게 결정되나? 현재 a 변수의 값에다 1을 더한 값이다. 아래의 코드를 보자. #1에서 a에 10이 저장되었다. #2에서 a+1 값을 구하면 11 값이 되고 #2 문장은 결국 "a=11"과 같이 실행된다. 쓰고보니 사족이 맞았다 ㅠ

파이썬 for문 마지막 값만 출력 - paisseon formun majimag gabsman chullyeog