파이썬 기본 문법: 2. 제어문
1. 조건문 (if 구문)
- 데이터의 처리는 단순한 사칙연산만 있는게 아니죠.
이럴땐 이렇게 처리하고, 저럴땐 저렇게 처리하고.. 우리가 원하는 여러가지 처리를 위한 공식이나 조건들이 있을것입니다.
컴퓨터는 우리가 머리로 생각하는 것처럼 이것저것 뚝딱뚝딱 처리하지 못합니다.
그냥 시키는대로.. 순서대로.. 쭈~욱 이어서 처리를 해 나가는거죠. - 그러면 우리는 무엇을 어떻게 시켜야할까요?
그냥 컴퓨터가 할 수 있는 방식으로 순서대로 쭉 이어서 가다가 이런 경우에는 이렇게 해라~라고 조건을 주고 그 조건에 따른 동작을 지정해 주면 되겠죠. - 이렇게 컴퓨터에게 처리를 위한 조건을 알려주는 구문을 조건문이라고 합니다.
- 가장 기본적인 조건문은 if ☆☆☆ else ○○○ 구문이 있습니다.
만약 ☆☆☆이면 ○○○를 해라. 라는 의미입니다.
#//file: `test.py` a = 10 b = 20 if a > b: print("a가 b보다 큽니다.") else: print("a가 b보다 크지 않습니다.")
- 그런데 여기서 특이한 것이 보입니다. if a > b: 와 같이 마지막에 콜론( : )이 붙어있습니다. 예전 코드에는 이런 것은 없었죠.
만약 a > b 라면.. 이라는 구문을 만족할때 우리는 “a가 b보다 큽니다.”라는 문자열을 출력하려고 하는데.. 그 구문을 만족할 때 과언 어디까지 실행을 해야 할까요? 그것을 지정해 주지 않으면 끝까지 흘러가 버리겠죠. 그래서 우리는 명령들을 블록이란 것으로 나누어서 표현합니다. 콜론( : )은 블록을 지정하는 구문의 끝에 붙여서 다음 줄부터 블록이 시작된다.. 라고 표시해 주는 것입니다.
- 그럼 블록의 끝은 어떻게 표시할까요?
- 파이썬에서는 블록의 구분을 들여쓰기를 이용해서 지정합니다.
소스코드를 보시면 print 구문이 몇 칸 안으로 들어와있죠? 저렇게 같은 간격으로 들여쓰기 된 구문들은 모두 같은 블록이다.. 라고 인식하는 것입니다. 그렇다면 블록의 끝을 지나면 들여쓰기의 간격을 원래대로 돌려두면 되겠죠. 위의 코드를 보시면 print 구문이 끝나고 들여쓰기가 해제되었습니다. 이제 블록은 끝났다는 뜻입니다.
그럼 if 구문에 따른 블록은 끝났으니 다음 명령어로 내려가겠죠. else 라는 구문을 만났습니다. 역시 콜론( : )을 통해서 블록의 시작을 알려주고 print 구문을 실행했습니다.이것으로 if ☆☆☆ else OOO 조건문이 끝났습니다.
그런데 조건이 딱 한 가지만 있진 않겠죠. 이럴땐 이렇게, 저럴땐 저렇게, 그 외에도 또 다른 조건을 동시에 지정할 수 있습니다. 이럴 경우에는 if ☆☆☆ else ○○○ 문을 중첩해서 사용하는 방법과 if ☆☆☆ elif ○○○ else ◇◇◇ 와 같이 if ☆☆☆ else ○○○ 구문이 확장된 표현을 사용하는 방법중 하나를 선택할 수 있습니다.
a = 20 b = 20 if a > b: print("a가 b보다 큽니다.") elif a == b: print("a와 b가 같습니다.") else: print("a가 b보다 작습니다.")
a = 30 b = 20 if a > b: print("a가 b보다 큽니다.") else: if a == b: print("a와 b가 같습니다.") else: print("a가 b보다 작습니다.")
- 위의 코드에서 a == b 라는 구문은 a와 b가 같다는 것을 의미합니다. 일반적으로 프로그래밍에서는 왼쪽 데이터, 변수와 오른쪽 데이터, 변수가 같다고 표현할 때에는 ==를 사용합니다. 왼쪽 항이 크다 (>), 왼쪽 항이 작다 (<)의 경우는 기존의 수학(산수?)과 같은 부호를 사용하는데 같다의 경우에는 기존의 등호(=)를 사용하지 않죠.
- 이유는 기존의 등호 (=)는 오른쪽 항의 값을 왼쪽 항에 넣는다는 의미로 사용되기 때문에 두 가지를 구분하기 위해서 입니다. 그래서 기존의 등호 (=)는 할당연산자(또는 대입연산자, 이항연산자)라고 불립니다. 파이썬에도 다양한 연산자가 있는데 앞으로 필요할 때마다 설명을 드리도록 하겠습니다.
- 위의 두 종류의 코드는 같은 결과를 출력해 줍니다. 여기서 우리가 알 수 있는 것은 if ☆☆☆ elif ○○○ else ◇◇◇ 구문만이 아니라.. 동일한 결과를 위한 코드의 작성에 정답은 없다.. 라는 것입니다. if ☆☆☆ elif ○○○ else ◇◇◇ 구문을 사용해도 되고 if ☆☆☆ else ○○○ 구문을 중첩해서 사용해도 됩니다. 나중에 배울 또 다른 조건문을 사용해도 되죠. 편하신 대로 코드를 작성하시면 됩니다.
- 물론 좀 더 실력이 좋아지고 컴퓨터가 처리하는 내부과정까지 이해하게 되면 각 구문들의 차이점이나 효율성 등을 따져서 작성하실 수 있습니다. 그런 프로그래밍을 위해서 더욱 빠르고 효율적인 처리가 가능하도록 정리된 것이 흔히 말하는 좋은 알고리즘이라고 하는 것들이죠. 아직까지는 거기까지 신경쓰지 않으셔도 됩니다.
- 지금까지 가장 기본적인 조건문에 대하여 살펴보았습니다.
2. 반복문
- 사람은 하기 힘들어하지만 컴퓨터가 가장 잘 하는 일은 무엇일까요? 바로 단순한 작업을 계속해서 반복하는 것이겠죠. 사람에게 단순 작업을 반복해서 시키면 금방 지겨워져서 집중해서 일을 하지 못할 것입니다. 실수도 늘어나겠죠. 그렇지만 컴퓨터는 그럴 일이 없으니 반복 작업을 시키기에는 가장 좋은 일꾼입니다. 따라서 반복작업을 지시하는 명령은 컴퓨터에게 일을 잘 시키기 위한 매우 중요한 수단입니다.
- 파이썬에서 사용하는 반복문은 크게 For 문과 While 문의 두 가지로 구분됩니다. 그 중에서 가장 많이 사용되는 것이 For 문인데.. For 문은 다양한 활용 형태를 가집니다.
2.1 for 문
2.1.1 기본형
먼저 가장 기본적인 형태를 살펴보겠습니다.
area = [1, 3, 4, 6, 7] for x in area: print(x)
- 먼저 1, 3, 4, 6, 7을 값으로 가지는 리스트를 area라는 변수에 할당했습니다. 그 다음의 for 문은 area 리스트 안의 값을 순서대로 하나씩 꺼내서 x에 할당하고, x에 하나의 값이 할당될 때 마다 print 문을 실행하라~ 라는 의미입니다. 그렇다면 area는 총 5개의 값을 가지고 있으니 print 구문을 5번 실행하겠죠. 그리고 출력되는 내용인 x는 area 리스트에서 순서대로 꺼낸 1, 3, 4, 6, 7이 순서대로 출력될 것입니다.
- for 구문에는 리스트 외에도 문자열(문자열도 엄밀히 말하면 문자들의 리스트입니다), 딕셔너리, 범위 등이 사용될 수 있습니다.
각각의 예제를 살펴봅시다.
# 문자열을 사용한 예 area_string = "Hello" for x in area_string: print(x)
# 딕셔너리를 사용한 예 area_dictionary = {'a':'Nice', 'b':'to', 'c':'meet', 'd':'you'} for x in area_dictionary: print(x)
딕셔너리를 사용한 예에서도 4개의 값을 잘 출력했습니다. 그런데 “Nice”, “to”, “meet”, “you”를 출력하고 싶은데 이것은 어떻게 할까요? for 구문이 사용하는 것은 딕셔너리에 포함된 값을 순서대로 꺼낸 것이기 때문에 “키:값”의 쌍에서 “키”만을 사용하고 있습니다. 그러면 우리는 area_dictionary 변수를 사용해서 출력해 줄 수 있겠죠. 키를 사용할 수 있으니까요.
area_dictionary = {'a':'Nice', 'b':'to', 'c':'meet', 'd':'you'} for x in area_dictionary: print(x, ':', area_dictionary[x])
키와 값이 모두 잘 출력되었습니다. 그런데 파이썬에서는 함수의 결과로 하나의 값만 받는 것이 아니라 두 개 이상의 값을 받을 수 있습니다. 그래서 area_dictionary 라는 딕셔너리 변수에서 우리가 사용할 수 있는 items라는 함수를 한 번 사용해 보겠습니다.
area_dictionary = {'a':'Nice', 'b':'to', 'c':'meet', 'd':'you'} for key, value in area_dictionary.items(): print(key, ':', value)
- 파이썬이 사용하는 모든 데이터 타입(형태)은 클래스라는 구조로 만들어져 있습니다. 클래스에 대한 것은 다음에 설명드리도록 하겠습니다. 지금은 클래스로 되어 있다는 것만 아셔도 됩니다. 아무튼.. 모든 데이터 타입은 클래스로 되어 있기때문에 클래스가 가지고 있는 다양한 함수를 끌어내어 사용할 수 있습니다.
- 바로 위의 예제에서 사용한 items( ) 라는 것도 딕셔너리 클래스가 가지고 있는 함수 중의 하나입니다. 딕셔너리 변수가 가지고 있는 각 항목들을 키와 값의 쌍으로 돌려주는 기능을 하죠. 따라서 for 구문을 실행하는데 area_dictionary가 가지고 있는 키와 값의 쌍을 순서대로 꺼내어서 그 개수만큼 for문의 블록 안에 있는 구문을 실행하라~ 라는 의미를 가지게 됩니다. 그리고 area_dictionary 변수의 키:값 쌍을 함께 받아와서 키는 key 변수에, 값은 value 변수에 넣어두었기 때문에 key 변수와 value 변수를 출력하는 print문을 블록에 사용했습니다.
- 앞에서 본 예제와 같은 결과를 확인할 수 있습니다.
2.1.2 range( ) 함수 사용
다음은 range 함수를 사용한 예제를 살펴보겠습니다.
for x in range(5): print(x)
for x in range(3, 5): print(x)
- range( ) 함수는 내부에 지정된 범위 안의 숫자를 돌려주는 함수입니다. 위의 예제 중 첫 번째는 먼저 0부터 5의 앞까지의 범위 안에 있는 숫자(0, 1, 2, 3, 4)를 순서대로 꺼내어 print 문으로 출력을 반복하라.. 라는 의미입니다. 이때, range( ) 함수 안의 범위는 위의 두 번째 예제와 같이 지정할 수 있습니다. 3부터 5의 앞까지의 범위 안의 숫자 (3, 4)를 순서대로 꺼내어 print 문으로 출력을 반복하라.. 라는 의미죠. 범위를 지정할 때 뒤에 있는 5는 5까지.. 의 의미가 아니라 5의 앞까지.. 의 범위입니다. 또한 range( ) 함수에서는 범위 안의 숫자 사이의 간격을 지정할 수도 있습니다.
다음 예제는 3부터 10의 앞까지의 숫자를 꺼내되, 각 숫자는 2씩 증가하도록 꺼내어서 print 문으로 출력하라.. 라는 의미입니다. 2만큼의 간격대로 3, 5, 7, 9가 출력된 것을 볼 수 있습니다.
for x in range(3, 10, 2): print(x)
그럼 for ~ range 문을 이용하여 구구단을 작성해 봅시다.
for dan in range(2, 10): print(dan, "단") for hang in range(2, 10): print(dan , "*", hang, "=", dan*hang) print()
2.1.3 for 문의 확장
- For문은 반복적인 처리를 위해서 사용하는 구문이라고 말씀드렸습니다. 그런데 그런 반복된 처리 속에서 반복 작업을 중단하고 나가야 한다거나 흐름에 변형을 주어야 할 때에는 어떻게 할까요? 앞의 예제어서 다루었던 if ~~ 구문을 이용해서 For 문을 빠져나간다거나.. 반복 작업 속에서 상황에 따라 다른 작업을 선택하도록 할 수도 있습니다. 실제로 많은 경우에 그런 방식으로 For문을 사용하고 있습니다.
- 파이썬에서는 이런 경우에 대하여 for ~ continue ~ break구문과 for ~ else 구문을 제공하고 있습니다. 사실 continue 구문은 직관적으로 눈에 들어오지 않는 편이어서 좀 헷갈리거나.. 이런 것을 왜 쓰지? 라고 하실 수도 있습니다. 그러나 continue 구문도 필요한 곳이 있으며, 또한 continue 구문은 프로세스가 어떻게 흘러가는지 익히기 위한 연습으로 좋습니다.
먼저 for ~ continue ~ break 구문을 살펴보겠습니다. for ~ continue ~ break 구문은 반복문을 수행하던 도중에 어떤 조건을 만나면 반복문을 계속 수행하고, 그 조건을 만족하지 않으면 반복문을 빠져나가도록 하는 구문입니다.
area = [1, 3, 4, 6, 7] for x in area: print(x) if x < 4: continue else: break
- 예제 코드에 continue, break를 적용한 예제입니다.
- 의미는 1, 3, 4, 6, 7 이라는 값을 가진 리스트 area에서 값들을 순서대로 꺼내어 반복문을 실행하라는 의미인데 1, 3, 4, 6, 7 값이 순서대로 x에 할당되고 해당하는 x 값을 출력하는 코드입니다. 이 때 x를 출력하고 난 다음, 만약 x가 4보다 작은 값이라면 for 구문을 계속 반복하고 x가 4 이상의 값이라면 for 구문을 빠져나가라는 의미입니다. 리스트 area의 세 번째 값인 4가 x에 할당되었을 때, if 문을 만나지만 if 문 이전에 print(x)를 만나기때문에 4까지 출력이 되고 종료하게 됩니다.
조금 변형시켜 볼까요?
area = [1, 3, 4, 6, 7] for x in area: if x < 4: print(x) continue else: break
- print(x) 구문을 if 문 안으로 넣어보았습니다. 이번에는 x = 4 인 경우 바로 for 문을 빠져나갔습니다. 그냥 continue 같은 것을 사용하지 않고 빠져나가는 조건만 사용해도 되지 않을까? 라고 생각하실 수 있습니다. 실제로도 continue 구문은 헷갈린다고 빠져나가는 조건만 사용하는 경우도 많이 있습니다.
다음 예제를 보시죠.
area = [1, 3, 4, 6, 7] for x in area: print(x) if x >= 4: break
- if 문에서의 조건만 살짝 바꾸어서 빠져나가는 구문만 적용한 예제입니다. 결과는 처음 본 예제와 같습니다.
이렇게 보면 continue 구문은 왜 있는 것일까? 라고 생각하실 수 있지만…뭐.. 그래도 어딘가에 필요하니까 만들어진 구문이겠죠. 어디에 필요한지 한 번 보도록 하죠.
area = [1, 3, 4, 6, 7] for x in area: print(x) if x < 4: continue else: break print("continue")
- 위의 예제를 보면… 분명히 print(“continue”) 구문이 for문 안에 있습니다. 그렇지만 실제로 출력이 된 적은 없습니다.
- continue 구문은 해당 조건을 만족할 경우 반복문을 계속 실행하라는 의미인데.. 중요한 것은 continue 구문 이후의 명령들은 생략하라~ 라는 의미라는 것입니다. 그렇기 때문에 print(“continue”)는 언제나 생략되어 출력되지 않은 것입니다.
하나 더 볼까요?
area = [1, 3, 4, 6, 7] for x in area: print(x) if x < 4: continue elif x > 6: break print("continue")
- 위의 예제에서는 if 문에서 다루는 조건은 x가 4보다 작은 경우는 continue, x가 6보다 큰 경우는 break를 만납니다. 그 외의 x에는 if문이 걸려있지 않죠. 그래서 x가 4보다 작은 경우는 print(“continue”)가 생략되었고 x가 6보다 커지면서 for문을 벗어나 버렸습니다. 그 조건 외에는 print(“continue”)가 실행된 것을 확인할 수 있습니다.
이런 차이가 있는거죠. 그런데 해당 조건을 벗어났다는 것은 위의 조건외의 모든 것이라고 할 수 있기때문에 다음의 예제처럼 구현할 수도 있습니다.
area = [1, 3, 4, 6, 7] for x in area: print(x) if x < 4: continue elif x > 6: break else: print("continue")
- 이처럼 각각의 목적에 따라 다르게 구현할 수 있고, 또 동일한 목적이 있는 구문이라도 프로그래머의 생각에 따라서 다르게 구현될 수 있습니다. 지난 글에서 “정답은 없다”라고 말씀드렸던 것처럼… 바로 이런 이야기입니다.
이번에는 for ~ else 구문을 살펴볼까요? for ~ else 구문은 반복문이 break 명령에 의해서 중단되지 않은 경우에만 else 안의 명령을 수행하라는 구문입니다.
area = [1, 3, 4, 6, 7] for x in area: print(x) else: print("finish")
- 위의 예제에서는 break 명령이 없습니다. 따라서 print(‘Finish’)는 잘 실행되었습니다.
그럼 중간에 break를 걸어볼까요?
area = [1, 3, 4, 6, 7] for x in area: print(x) if x > 6: break else: print("finish")
- x가 6보다 큰 경우 break를 걸어보았습니다. print(x) 명령은 if문 이전에 있기 때문에 break는 걸려있지만 이미 출력은 모두 완료되었죠. 그러나 어쨋든 break로 for문이 중단된 것이기때문에 else 구문 안의 print(‘Finish’)는 실행되지 않았습니다.
그럼 이렇게 바꿔볼까요?
area = [1, 3, 4, 6, 7] for x in area: print(x) if x > 7: break else: print("finish")
- x가 7보다 큰 경우에 break를 걸었습니다. 그러나 리스트 area의 마지막 값인 7이 x > 7을 만족하지 않았기때문에 if문을 만족하기 전에 for문이 끝나버렸습니다. break 명령에 걸리지 않은 것입니다. 따라서 “Finish”는 잘 출력되었습니다.
- 여기까지 해서 for ~ continue ~ break 구문과 for ~ else 구문을 살펴보았습니다.
2.2 while 문
- while 문은 for 문과 다르게 반복하기 위한 조건이 주어진다는 점이 특징입니다. while 문에 따라오는 조건을 만족하는 동안 계속해서 반복 작업을 수행하라.. 라는 의미입니다.
예제 코드를 먼저 보겠습니다.
x = 1 while x < 10: x = x + 1 if x < 5: continue print(x) if x > 7: break
- 예제 코드의 내용은 먼저 x의 초기 값을 1로 잡아 두고 x가 10보다 작은 동안에는 계속 반복 작업을 시키는 것입니다. “x가 10보다 작은 동안”이라는 말은 “x < 10” 이라는 조건이 “참(True)”이 되는 경우를 말하죠. 즉 주어진 x에 대하여 x < 10을 만족한다면 계속 반복 작업을 시키고, x < 10을 만족하지 않는다면, 다시 말해서 x가 10 이상의 값을 가지게 된다면 반복 작업을 중단시켜라.. 라는의미입니다.
- 그렇다면 x의 값이 변하지 않으면 while 문은 영원히 반복하게 되겠죠. 그래서 반복 작업을 한 번 수행할 때마다 x의 값을 1씩 증가시킵니다. x = x + 1 구문은 x의 값에 1을 더한 값을 다시 x로 할당하여라.. 라는 명령입니다. 즉 x의 값을 x + 1로 바꿔주라는… 1을 증가시키라는 뜻이죠. 그러면 반복 작업을 한 번 수행할 때마다 x의 값은 2, 3, 4, … 와 같이 계속 증가하게 될 것입니다.
- 이렇게 x의 값을 증가시키도록 명령하고 나서 조건문이 들어왔습니다. 만약 x가 5보다 작으면 continue 명령에 따라 뒤에 따라오는 명령은 무시하고 다시 처음부터 작업을 반복합니다. x의 처음 값은 1이니까 1씩 증가하다가 x = 5가 되는 순간부터 continue 명령을 벗어나서 print(x)를 실행하게 됩니다. 이때 print(x) 명령 다음에 다시 x > 7인 경우에 대한 조건문이 들어왔죠. x가 7보다 커지면 while 반복문을 빠져나가라는 명령입니다. x = 5, 6, 7까지 print문을 수행하고 나서, 여전히 x > 7을 만족하지 않으니까 한 번 더 반복 작업을 실행합니다. x = 8이 되었고 첫 번째의 조건문을 만족하지 않으니까, 즉 첫 번째 조건의 결과가 False가 되니까 print(x)를 수행합니다. 8까지 출력이 되었죠.
- 다음으로 두 번째의 조건문을 만났습니다. 지금 x의 값은 8이니까 x > 7 이라는 조건문을 만족합니다. 그럼 break 명령에 따라서 반복문을 빠져나가게 됩니다. 그럼 결과는 5, 6, 7, 8의 네 개의 숫자가 출력이 되겠죠.
- 이렇게 while 문을 이용한 반복문을 살펴보았습니다.
- 그런데 우리가 사용하는 많은 프로그램들은 직접 종료시키지 않으면 무한정 반복하는 프로그램들이 대부분이죠. 공부할 때 사용하는 예제코드에서는 처음부터 특정 조건을 주고 반복을 시키지만 일반적인 프로그램들은 그냥 계속 동작합니다. 대표적인 예로 윈도우, 리눅스와 같은 OS, 즉 운영체제 프로그램을 들 수 있습니다. 우리가 컴퓨터를 종료시키지 않으면 계속… 끝없이 동작합니다.
이처럼 강제로 무한루프(끝없이 반복, 즉 루프를 도는 구조)를 지정하려고 하면 어떻게 해야 할까요? 앞에서 while문은 따라오는 조건을 만족하는 한 계속 반복한다고 말씁드렸습니다. 그렇다면 그 조건이 언제나 참(True)이 되면 되겠네요.
x = 1 while True: x = x + 1 if x < 5: continue print(x) if x > 7: break
- 아래의 예제는 무한루프를 돌게 됩니다.
- Colab을 사용 중이시라면 적당한 시점에 셀의 좌측상단에 있는 (▶) 또는 (◼) 버튼을 눌러서 중지시켜주세요.
로컬 시스템의 자체 가상환경을 사용 중이시라면 Ctrl-C를 눌러서 중지시켜주세요.
x = 1 while 1: print(x) x = x + 1
예제 코드에서 사용한 것처럼 그냥 조건문 자리에 True를 넣어버리면 해당 반복문은 break를 만날때까지 무한루프를 돌게 됩니다. 여기서 True (참) / False (거짓) 라고 하는 값은 boolean 값(논리 값이라고도 합니다)이라고 부르며 어떤 조건에 대하여 참과 거짓을 나타내는 두 개의 값을 가지는 자료형(데이터 타입)입니다. 참(True)은 1, 거짓(False)은 0으로 할당이 되어 있기 때문에 while문에 따라오는 조건에 True 대신 1을 넣어주어도 동일하게 동작합니다. 그렇지만 보기 쉽게 True / False를 이용하는 것을 권장하기도 합니다.
x = 1 while 1: x = x + 1 if x < 5: continue print(x) if x > 7: break
- 여기까지 해서 While문을 이용한 반복문에 대하여 알아보았습니다.
- 지금까지 살펴본 데이터 형, 기본적인 연산 및 명령, 조건문, 반복문 정도만 잘 활용해도 어지간한 프로그램은 구현할 수 있습니다. Windows 10과 같은 OS를 포함해서… 아무리 큰 프로그램이라도 각 기능별로 하나하나 쪼개나가면 그 밑바닥에는 결국 위의 4가지 정도가 기본이 되어 구현됩니다. 그 이후에는 더 고차원적인 연산, 기능을 구현하기 위해서 점점 코드를 확장하고 키워나가는것입니다.