05-4 반복문
윤혜민·박현규 · 26 / 30 절이제 좀 더 나아가봅시다. 이미 반복문은 리스트나 딕셔너리에서 for문으로 만난 적이 있습니다. 그때는 리스트나 딕셔너리의 구조에 집중하느라 for문의 동작 원리에 대해서는 깊게 살펴보지 않았습니다. 그리고 반복문에는 for문만 있는 것도 아닙니다. while문도 있습니다. 여기서는 반복문 while문부터 for문까지 순서대로 알아보겠습니다.
while문 기초 연습하기
while문은 조건식이 True인 동안 계속해서 코드를 반복 실행합니다. 조건식은 이미 if문에서 본 적이 있는 개념입니다. 우선 while문의 코드 예를 입력하고 실행해본 다음 while문의 동작 원리를 설명하겠습니다.
count = 1
while <span class="mark">count <= 5</span>:
print(f"{count}번째 반복입니다.")
count = count + 1
[실행 결과]
1번째 반복입니다.
2번째 반복입니다.
3번째 반복입니다.
4번째 반복입니다.
5번째 반복입니다.
코드의 하이라이트가 조건식입니다. 그럼 while문은 어떻게 동작할까요? 다음 글을 읽어봅시다.
조건식을 검사한다.
조건식이 True이면
1. while문의 코드 블록을 실행한다.
2. 1로 돌아간다.
- 조건식이 False이면
1. while문을 종료한다.
while문은 조건식을 검사한 후 True, False에 따라 while문의 코드 블록의 실행 여부를 결정합니다. True이면 while문의 코드 블록을 실행하고 다시 1로 돌아갑니다. 그러다가 False가 되면 while문을 종료합니다.
이때 조건식이 언젠가는 False가 될 수 있도록 코드 블록을 설계하는 것이 중요합니다. 코드 블록 마지막에 count = count + 1이라는 코드가 바로 그것입니다. 현재 count의 값에 1을 더하여 그것을 count에 저장하는 것입니다. 그러면 다음 조건식을 검사할 때의 count는 2가 됩니다. 그러면 코드 블록을 실행할 때마다 3, 4, 5로 점차 값이 증가하게 되겠네요. 결국 count가 6이 되는 시점이 올 겁니다. 마침내 6 <= 5의 조건식의 평가 값은 False가 되어 while문의 실행이 중단될 것입니다. 정리하자면 작성한 코드는 다음과 같이 동작합니다.
count는 1이므로 조건식이 True, 코드 블록 실행(print( ) 함수 실행, count를 2로 만들기)
count는 2이므로 조건식이 True, 코드 블록 실행(print( ) 함수 실행, count를 3으로 만들기)
...
count는 6이므로 조건식이 True, while문 종료
while문의 동작 방식을 이해하는 건 별로 어렵지 않을 것입니다. 다만 조건식이 False가 되도록 만드는 코드 블록의 설계가 중요합니다. 그러면 만약 조건식이 False가 될 수 없다면 어떻게 될까요?
while문의 무한 루프
while문을 사용할 때 가장 주의하여 사용해야 할 것은 바로 무한 루프입니다. 왜냐하면 while문의 조건식이 True로 유지되면 프로그램이 멈추지 않고 계속 실행되기 때문입니다. 다음은 count 변수에 1을 저장한 다음 while문의 코드 블록에서 값을 변경하지 않아 조건식 count <= 5가 무한히 True로 평가되는 코드입니다. 코드를 실행하면 코드를 무한 실행합니다.
count = 1
while count <= 5:
print(f"{count}번째 반복입니다.")

코드를 실행한 뒤에 멈추는 방법은 사람이 개입해서 강제 종료하는 방법 뿐입니다. [Ctrl + C]를 눌러 프로그램을 강제로 종료하세요.
무한 루프는 위험한 건가요?
그러면 무한 루프는 위험한 걸까요? 그렇지는 않습니다. 여러분 곁에는 유용한 무한 루프로 구성된 프로그램도 있습니다. 바로 서버입니다. 서버는 24시간 사용자의 요청을 대기해야 하는 프로그램입니다. 그래서 개념을 설명하자면 이런 코드 구성을 생각해볼 수 있습니다.
[Note] 실행되는 코드가 아니므로 그냥 눈으로 살펴보기 바랍니다.
# 서버의 기본 동작 원리 (개념적 표현)
while True:
request = wait_for_request() # 요청이 올 때까지 대기
response = process_request(request) # 요청 처리
send_response(response) # 응답 전송
# 그리고 다시 처음으로 돌아가서 다음 요청 대기
코드를 보면 while True:라고 떡하니 무한 루프로 구성되어 있습니다. 그러면서 무한하게 다음 작업을 수행합니다.
사용자의 요청을 기다리기 : wait_for_request( )
사용자의 요청 처리하기 : process_request( )
요청에 맞는 응답 전송하기 : send_response( )
사용자의 요청이 언제 올지 모르기 때문에 무한히 요청을 기다리면서 요청이 오면 요청을 처리하고 응답을 전송하는 코드로 구성되어 있습니다. 물론 실제 서버는 이보다 훨씬 복잡하게 구성되어 있습니다. 이정도면 while문의 기초와 무한 루프의 개념이 잘 이해되었을 것입니다.
[Note] 서버의 개념까지 들어가며 설명하는 내용이 좀 과하다 느껴질 수도 있겠습니다. 하지만 무의미한 무한 루프를 실행해서 공부하기보다는 이렇게 설명하는 편이 여러분의 기억에 잘 남을 거라 믿으며 글을 써봤습니다.
break 기초 연습하기
이제 break를 알아볼 때가 됐습니다. 앞에서 while문을 종료할 방법으로 조건식을 False로 만들면 된다라고 이야기했습니다. 하지만 다른 방법으로도 while문을 종료할 수 있습니다. 바로 break입니다. break는 키워드인데 뜻을 그대로 풀이하면 '깨다'라는 뜻입니다. 말 그대로 반복 흐름을 깨고 나오는 용도로 사용합니다. 반복 흐름을 깨야 하므로 상식적으로 생각했을 때는 단순 while문에서 사용하기는 어렵고 while문과 if문 류를 조합해야 의미 있게 사용할 수 있습니다. 다음 코드를 실행해봅시다.
count = 1
while count <= 10:
print(f"{count}번째 반복")
if count == 5:
print("5에 도달했습니다. 반복을 중단합니다.")
break
count = count + 1
print("반복문이 종료되었습니다.")
[실행 결과]
1번째 반복
2번째 반복
3번째 반복
4번째 반복
5번째 반복
5에 도달했습니다. 반복을 중단합니다.
반복문이 종료되었습니다.
코드를 실행해보면 count 변수의 값이 1로 시작해서 반복할 때마다 count = count + 1로 count 변수의 값을 1만큼 누적합니다. 이때 if문에서 count == 5로 변수의 값이 5가 되면 "5에 도달했습니다. 반복을 중단합니다."를 출력하고 break로 반복의 흐름을 깨고 나옵니다. 반복문 자체의 조건식은 count <= 10으로 count가 11이 되어야 False가 되어 종료되는 구조지만 if count == 5:에서 break 키워드를 사용하여 반복문을 종료한 것입니다. 코드 흐름을 그림으로 나타내면 다음과 같습니다.

그림을 보면 count를 출력한 다음 count가 5인지 아닌지 검사하여 5라면 break를 만나 종료하는 모습이 잘 보입니다. 이처럼 break 키워드는 반복문 안에서만 사용할 수 있으며, break 키워드를 만나면 반복문은 즉시 종료됩니다.
continue 기초 연습하기
continue 키워드는 현재 반복을 중단하고 다음 반복으로 바로 넘어갈 때 사용합니다. break는 반복문을 완전히 빠져나오지만, continue는 while문의 처음으로 돌아가게 합니다. 즉, continue를 만나면 while문의 조건식으로 다시 돌아갑니다. 다음 코드를 실행해봅시다.
count = 0
while count < 10:
count += 1
if count == 5:
print(f"{count}번은 건너뜁니다.")
continue
print(f"{count}번째 반복 실행")
print("반복문 종료")
[실행 결과]
1번째 반복 실행
2번째 반복 실행
3번째 반복 실행
4번째 반복 실행
5번은 건너뜁니다.
6번째 반복 실행
7번째 반복 실행
8번째 반복 실행
9번째 반복 실행
10번째 반복 실행
반복문 종료
코드를 실행해보면 5번째 반복일 때 continue를 만나서 "5번째 반복 실행" 메시지는 출력하지 않고, 다시 처음인 조건식으로 돌아갑니다. 이후 반복문을 진행하여 10번까지 모두 실행합니다.
continue 응용 연습하기
continue는 처음 공부하면 도대체 어디서 사용하면 좋을지 감을 잡기 어려운 키워드입니다. 다음 재고 처리 프로그램 예를 통해 감을 잡아봅시다.
[Note] 여기서 딕셔너리를 요소로 갖는 리스트를 사용합니다. 개념이 가물가물하다면 리스트, 딕셔너리로 돌아가 다시 들춰보고 와도 좋습니다.
products = [
{"name": "사과", "stock": 10},
{"name": "바나나", "stock": 0},
{"name": "오렌지", "stock": 5},
{"name": "포도", "stock": 0},
{"name": "수박", "stock": 3}
]
print("판매 가능한 상품:")
index = 0
while index < len(products):
product = products[index]
index += 1
if product["stock"] == 0:
continue
print(f"- {product['name']}: {product['stock']}개")
[실행 결과]
판매 가능한 상품:
- 사과: 10개
- 오렌지: 5개
- 수박: 3개
조건식은 while index < len(products):입니다. len( ) 함수는 리스트에서 알아본 길이를 반환하는 함수입니다. products 리스트에는 총 5개의 딕셔너리가 들어 있으므로 5를 반환합니다. 따라서 index가 0부터 시작해서 4가 될 때까지 반복문을 실행하고 5가 되면 반복문을 종료합니다. 이때 반복문 안에서 if product["stock"] == 0:로 딕셔너리의 키가 "stock"인 값이 0인지 검사하고 있습니다. 만약 0이면 continue를 실행하여 while문의 처음인 조건식으로 돌아갑니다. 한마디로 products 리스트의 내용물을 확인해서 재고가 있는 것만 출력하는 프로그램입니다. 다음 그림을 보며 프로그램의 구조를 다시 이해해봅시다.

그림을 보면 처음에 index가 len(products)에서 검사한 값보다 작은지 검사하여 반복문 실행 여부를 결정합니다. 이때 stock == 0이면 continue를 만나 상품을 출력하지 않고 다시 처음으로 돌아옵니다. continue는 이정도만 공부하고 나중에 필요할 때마다 사용하겠습니다.
while문 응용 연습하기
while문은 조건식이 False가 될 때까지 반복하는 특징이 있으므로 이를 잘 활용하면 반복 작업을 해야 하는 상황에 매우 유용합니다. 이때 break, continue 키워드도 적절히 사용하면 좋겠죠?
ATM기 시뮬레이션 프로그램 만들기
ATM기 시뮬레이션 프로그램을 만들어봅시다. 다음 코드는 잔고가 5만원이 남아 있고, 인출 시 수수료 1천원을 내야 한다는 전제가 있는 ATM기 시뮬레이션 프로그램입니다. 메뉴에서 1, 2, 3, 4를 선택하여 ATM기의 동작을 흉내냈습니다.
[Note] 이번 코드는 좀 깁니다. 혹시라도 파이썬 인터프리터 셸에서 실습하고 있었다면 이번에는 비주얼 스튜디오 코드나 커서에서 실습을 진행하기 바랍니다.
balance = 50000
fee = 1000
print(f"잔액: {balance:,}원 (수수료: {fee:,}원)")
while True:
print("\n[인출 금액 선택]")
print("1. 5,000원")
print("2. 10,000원")
print("3. 50,000원")
print("4. 취소")
choice = input("선택하세요 (1/2/3/4): ")
if choice == "1":
amount = 5000
elif choice == "2":
amount = 10000
elif choice == "3":
amount = 50000
elif choice == "4":
print("거래를 취소합니다.")
break
else:
print("잘못된 선택입니다.")
continue
print(f"\n{amount:,}원 선택")
if amount + fee <= balance:
balance -= (amount + fee)
print(f"V 인출 완료! 남은 잔액: {balance:,}원")
else:
print(f"X 잔액 부족 (필요: {amount + fee:,}원)")
[실행 결과]
잔액: 50,000원 (수수료: 1,000원)
[인출 금액 선택]
1. 5,000원
2. 10,000원
3. 50,000원
4. 취소
선택하세요 (1/2/3/4): 2
10,000원 선택
V 인출 완료! 남은 잔액: 39,000원
[인출 금액 선택]
1. 5,000원
2. 10,000원
3. 50,000원
4. 취소
선택하세요 (1/2/3/4): 3
50,000원 선택
X 잔액 부족 (필요: 51,000원)
[인출 금액 선택]
1. 5,000원
2. 10,000원
3. 50,000원
4. 취소
...생략...
프로그램을 실행해보면 [인출 금액 선택]을 알리면서 '다음과 같이 선택하세요 (1/2/3/4):' 메시지를 띄운 상태에서 대기할 것입니다. 이건 input( ) 함수가 실행된 것입니다. 이 함수는 앞에서 써본 적이 없는 함수이므로 여기서 간단히 설명하겠습니다.
사용자의 키보드 입력을 기다리는 input( ) 함수
input( ) 함수는 전달한 문자열을 출력하고 사용자의 키보드 입력과 [Enter]를 기다립니다. 그리고 키보드 입력 후 [Enter]를 누르면 키보드로 입력한 값을 코드로 반환합니다. 아직은 우리가 함수를 배운 상태는 아니므로 반환이 무엇인지는 제대로 이해할 필요는 없습니다. 어떤 값을 키보드로 입력하고 [Enter]를 누르면 그 입력한 값이 코드로 들어간다는 것만 이해하면 됩니다. 코드와 실행 상태를 매치하면 다음 그림을 생각해볼 수 있습니다.

그림을 보면 직관적으로 'input( ) 함수는 메시지를 출력한 상태에서 키보드 입력을 기다리고 입력한 값을 코드에서 다시 사용하게 해주는 거구나'라고 이해할 수 있습니다. 아마 이정도 설명이면 input( ) 함수의 동작 방식은 충분히 이해되었을 것입니다. 다시 ATM기 코드 설명으로 돌아가보죠.
while문의 조건식을 True로 고정했으므로 무한 루프 구조입니다. 따라서 종료 조건을 정하는 것이 중요하겠죠? 종료 조건은 ifelifelse문 속에 있습니다. ifelifelse문을 다시 살펴봅시다.
...생략...
if choice == "1":
amount = 5000
elif choice == "2":
amount = 10000
elif choice == "3":
amount = 50000
elif choice == "4":
print("거래를 취소합니다.")
break
else:
print("잘못된 선택입니다.")
continue
...생략...
코드를 보면 choice 변수에 input( ) 함수로 받은 값이 무엇인지에 따라 다르게 처리하고 있습니다. 하이라이트로 표시한 부분이 반복문 종료 조건입니다. choice의 값이 4가 되면 break를 통해 반복문을 빠져나오겠네요. 그리고 사용자가 잘못 입력하거나 의도적으로 다른 값을 입력할 것을 대비한 코드가 else문과 continue의 조합입니다. else문을 통해 1~4를 제외한 모든 입력을 continue로 처리하여 반복문의 시작 지점으로 되돌릴 수 있으니 무한 루프를 유지할 수 있겠네요.
코드의 길이가 길어서 대체 어떻게 프로그램이 돌아가는지 파악하기 어렵고, 정신이 없을 수 밖에 없습니다. 침착하게 다음 그림과 함께 프로그램의 로직을 살펴봅시다.

그림을 살펴보면 프로그램의 초기값인 잔액과 수수료를 설정하고 메뉴를 출력하여 입력을 유도합니다. 무한 루프는 다음 두 조건 하에서만 유지됩니다. 유일한 종료 조건은 4를 입력했을 때입니다.
- 사용자가 1~3을 입력했을 때 : 인출 로직 수행
1. 잔액이 충분하다면? : 인출 메시지 출력
2. 잔액이 충분하지 않다면? : 부족 메시지 출력
- 사용자가 1~4 이외의 값을 입력했을 때 : 다시 메뉴 출력
이정도면 while문, break, continue는 충분히 이해가 되었을 겁니다. 사용자의 입력을 기다리는 input( ) 함수도 꼭 기억해두기 바랍니다. 앞으로 종종 사용하겠습니다.
for문 기초 연습하기
이번에는 또다른 반복문 문법인 for문을 공부하겠습니다. while문이 조건식이 True일 때 동작하는 구조였다면, for문은 정해진 항목들을 하나씩 순회하는 구조입니다. 이미 for문은 리스트를 공부하면서 만난적이 있습니다. 리스트에서 공부했던 이유가 바로 이 순회라는 개념 때문입니다. 순회 개념은 다음 코드를 작성하여 실행해보고 천천히 알아보겠습니다. 다음은 for문으로 작성한 간단한 코드입니다.
fruits = ["사과", "바나나", "오렌지"]
for fruit in fruits:
print(f"{fruit}를 먹었습니다.")
print("모든 과일을 다 먹었습니다.")
[실행 결과]
사과를 먹었습니다.
바나나를 먹었습니다.
오렌지를 먹었습니다.
모든 과일을 다 먹었습니다.
코드를 실행하면 fruits 리스트에 있는 값을 순서대로 끝까지 출력합니다. for fruit in fruits:는 다음과 같이 2개의 구조로 나눠서 이해하면 됩니다.
in fruits : fruits 변수 안에 순회할 요소가 있다면
for fruit : 각 요소를 fruit에 전달해서 반복(for)해라
글로도 잘 이해되지 않는다면 이런 그림을 떠올리면 됩니다.

리스트에 있는 내용을 끝까지 훑으면 반복문을 종료하네요. 이처럼 for문은 반복할 대상이 반드시 필요하고, 반복할 대상은 순회할 수 있는 것이어야 합니다. while문은 조건식에 따라 반복했지만 for문은 반복 대상에 따라 반복하는 차이가 있군요. 이제 순회 개념을 공부할 때가 되었습니다. 문법 공부에서 벗어나 잠시 순회라는 개념을 이해하고 돌아옵시다.
순회란 무엇인가?
순회란 어떤 자료구조에 있는 요소를 체계적으로 방문하는 과정을 의미합니다. 프로그래밍 공부가 처음이라면 이 설명이 잘 이해되지 않을 수도 있습니다. 비유하자면 여러분이 설문조사를 하기 위해 아파트를 방문한 설문조사원일 때 아파트의 세대와 아파트의 구조 자체를 자료구조라고 생각하면 됩니다. 그리고 아파트의 모든 세대에 방문하는 과정 자체를 순회라고 이해하면 됩니다.

파이썬에는 순회를 할 수 있는 자료구조가 있습니다. 이미 앞에서 공부했던 리스트, 튜플, 딕셔너리, 문자열, 집합이 순회할 수 있는 자료구조입니다. 그래서 이런 자료구조들은 for문에 바로 사용하여 순회할 수 있습니다. 다음은 각 자료구조를 for문으로 순회하는 4가지 코드와 실행 결과입니다.
리스트 순회하기
이미 앞에서 작성했던 코드와 크게 다르지 않습니다. 빠르게 실행해서 다시 확인해봅시다. 코드를 실행하면 리스트에 있는 요소를 순서대로 출력합니다.
fruits = ['apple', 'banana', 'cherry']
for fruit in fruits:
print(fruit)
[실행 결과]
apple
banana
cherry
튜플 순회하기
튜플도 마찬가지입니다. 용법은 완전히 같습니다.
numbers = (10, 20, 30)
for num in numbers:
print(f"숫자: {num}")
[실행 결과]
숫자: 10
숫자: 20
숫자: 30
문자열 순회하기
문자열은 문자열 자체가 문자를 여러 개 담고 있는 형태이므로 문자를 순회할 수 있습니다.
message = "Hello"
for char in message:
print(char)
[실행 결과]
H
e
l
l
o
딕셔너리 순회하기
딕셔너리는 for문에 전달하는 형태에 따라 키를 순회할지, 값을 순회할지, 키와 값을 모두 순회할지 정할 수 있다고 이야기했습니다. 다음과 같이 딕셔너리만 for문에 전달하면 키를 순회합니다.
student = {'name': 'Alice', 'age': 20, 'city': 'Seoul'}
# 키만 순회
for key in <span class="mark">student</span>:
print(key)
[실행 결과]
name
age
city
만약 값을 순회하고 싶다면 values( ) 함수를 조합해야 한다고 설명했습니다. 다음은 values( ) 함수를 조합하여 값을 순회하는 코드입니다.
student = {'name': 'Alice', 'age': 20, 'city': 'Seoul'}
# 값만 순회
for key in <span class="mark">student.values( )</span>:
print(key)
[실행 결과]
Alice
20
Seoul
만약 키와 값을 순회하고 싶다면 items( ) 메서드를 조합해야 한다고 설명했습니다. 다음은 items( ) 함수를 조합하여 키와 값을 순회하는 코드입니다.
student = {'name': 'Alice', 'age': 20, 'city': 'Seoul'}
for key, value in <span class="mark">student.items( )</span>:
print(f"{key}: {value}")
[실행 결과]
name: Alice
age: 20
city: Seoul
순회 코드를 여러 번 작성하고 실행하다보면 슬슬 순회가 어떤 개념인지 감이 잡힐 겁니다. 순회는 이처럼 자료구조를 중심으로 모든 값을 처음부터 끝까지 꺼내는 작업이므로 '데이터 개수에 맞춰서 반복하고 싶다'라는 생각이 들 때 사용하면 좋습니다. 사실 많은 작업이 데이터 개수에 맞춰 반복하는 것이므로 지금 작성한 코드 패턴은 정말 자주 쓰이게 될 겁니다.
while문과 for문은 구분해서 쓰면 좋습니다
while문은 조건식에 따라 반복하는 구조를 가지고 있으므로 특정 상황이나 조건이 강조될 때 적합합니다. 반면 for문은 어떤 데이터를 중심으로 순회하며 반복하는 구조를 가지고 있으므로 데이터를 반복해야 하는 상황이 강조될 때 적합합니다. 한마디로 for문은 '이 데이터들을 처리하자'는 느낌이 들 때 사용하면 좋고, while문은 '이 상황이 될 때까지 계속하자'는 느낌이 들 때 사용하면 좋습니다. 다음 코드는 [0, 1, 2] 리스트를 for문, while문에 사용한 예입니다. 코드를 입력하면서 그 상황에 대한 적절함을 느껴봅시다.
my_numbers = [0, 1, 2]
# 리스트 중심으로 반복
print("=== for문 사용 ===")
for i in my_numbers:
print(f"반복 중 확인한 요소 {i}")
print("\n=== while문 사용 ===")
count = 0
while count < 3:
print(f"반복 중 확인한 요소 {my_numbers[count]}")
count = count + 1
[실행 결과]
=== for문 사용 ===
반복 중 확인한 요소 0
반복 중 확인한 요소 1
반복 중 확인한 요소 2
=== while문 사용 ===
반복 중 확인한 요소 0
반복 중 확인한 요소 1
반복 중 확인한 요소 2
모두 실행 결과는 같지만 작성한 코드의 양상은 다릅니다. 특히 while문이 많이 어색합니다. 다음과 같은 이유가 while문이 어색하다 느껴지게 만듭니다.
리스트에 접근하기 위해 인덱싱을 사용하기 위해 count 변수를 준비했습니다.
조건식으로 count가 3보다 작은지 검사해야 합니다.
반복문 내 마지막에 count = count + 1로 count의 값을 관리해야 종료 조건을 달성할 수 있습니다.
어차피 리스트의 요소를 순회해야 한다면 구태여 이렇게 코드를 작성할 필요가 없습니다. for문은 그에 비해 코드가 깔끔합니다. 인덱싱을 사용하지도 않았고, 종료 조건을 따로 마련하지도 않았습니다. 어차피 for문은 리스트의 처음부터 끝까지 순회하며, 순회를 마치면 알아서 종료하기 때문입니다. 따라서 데이터 중심으로 순회해야 할 때는 for문을 사용하는 것이 훨씬 좋습니다.
for문 응용 연습하기
for문은 데이터 중심으로 다양한 코드를 작성해보고 실행하면 자연스럽게 이해가 느는 문법입니다. 다양한 응용 예를 실행해보면서 for문 공부를 마쳐봅시다.
조건문과 결합하여 짝수 판별하기
리스트에 1부터 10까지의 자연수가 있을 때 짝수만 판별하는 코드는 다음과 같이 작성하면 됩니다. 순회할 수 있는 자료구조 속에서 특정 조건에 맞는 데이터를 골라낼 때 유용합니다.
# 짝수만 골라내기
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = []
for num in numbers:
if num % 2 == 0:
even_numbers.append(num)
print(f"짝수 목록: {even_numbers}")
[실행 결과]
짝수 목록: [2, 4, 6, 8, 10]
코드를 보면 짝수만 담을 even_numbers 변수를 따로 준비해두고, even_numbers.append(num)으로 순회 중 짝수로 걸러낸 값을 even_numbers에 추가합니다. 따라서 실행 결과는 짝수 리스트가 출력됩니다. for문으로 numbers를 순회할 때 순회 요소 num을 if num % 2 == 0에서 검사하여 짝수만 잡아 넣는다고 생각하면 됩니다.
합계와 평균 구하기
만약 학생 점수를 담은 리스트가 있을 때 합계와 평균을 구한다면 다음과 같이 코드를 작성하면 됩니다. 실행 결과를 보면 합계인 총점과 평균을 잘 계산해준 것을 볼 수 있습니다.
# 점수 리스트에서 합계와 평균 계산
scores = [85, 92, 78, 90, 88]
total = 0
for score in scores:
total += score
average = total / len(scores)
print(f"총점: {total}점")
print(f"평균: {average}점")
[실행 결과]
총점: 433점
평균: 86.6점
range( ) 함수와 인덱스 활용하기
for문을 사용해도 인덱스를 반복문 내에서 사용해야 할 일이 가끔씩은 있습니다. 예를 들어 과일 리스트가 있을 때 과일의 순서에 따라 번호를 함께 출력하고 싶다면 이렇게 코드를 작성하면 됩니다.
# 순서 번호와 함께 출력하기
fruits = ['사과', '바나나', '체리', '포도']
for i in range(len(fruits)):
print(f"{i+1}. {fruits[i]}")
[실행 결과]
1. 사과
2. 바나나
3. 체리
4. 포도
len( ) 함수는 길이를 측정하는 함수이므로 4를 반환합니다. 그리고 range( ) 함수가 4를 다시 감쌉니다. range(4)는 for문과 조합하면 순서대로 0, 1, 2, 3을 반환합니다.
<1:1코칭> range( ) 함수는 어떻게 동작하나요?
range( ) 함수는 다음 3가지 형태로 사용할 수 있는데, range( ) 함수는 for문이 순회할 수 있는 이터러블 객체를 반환합니다.
# range( ) 함수의 사용 예
range(stop) # 0부터 stop-1까지
range(start, stop) # start부터 stop-1까지
range(start, stop, step) # start부터 stop-1까지 step 간격으로
그래서 for문의 동작을 보면 range(4)가 '[0, 1, 2, 3]이라는 리스트를 만드는 건가?'라고 오해하기 쉬운데 사실 그렇지는 않습니다. 아무튼 순회할 수 있는 무언가'라는 애매한 표현과 이터러블 객체라는 개념은 여러분이 지금은 명쾌하게 알 수 없습니다. 어쩔 수 없습니다. 지금 당장 이것을 구체적으로 설명하자면 너무 설명이 길어지고 알 필요 없는 내용까지 설명해야 합니다. 지금은 range( ) 함수를 for i in range(3)과 같이 for문에 조합하면 3번 반환할 수 있는 용도로 사용할 수 있다 정도로만 이해해둡시다.
</1:1코칭>
중첩 반복문 개념 알아보고 기초 연습하기
지금까지 배운 반복문 문법을 중첩해서 사용하면 중첩 반복문이라고 합니다. 중첩 반복문을 가장 쉽게 이해할 수 있는 예는 구구단입니다. 여러분이 구구단을 외울 때를 생각해봅시다. 어떻게 외우나요?

우선은 2단부터 시작해서 1부터 9까지 곱하며 외웁니다. 그런 다음에는 3단, 4단, ... 9단까지 이것을 반복합니다. 결국 구구단을 외우는 구조는 각각의 단을 외우는 작은 반복과 그것을 다시 크게 반복하는 구조를 가진다는 걸 알 수 있습니다. 결론은 구구단을 외우는 구조 자체가 중첩 반복문입니다. 이 개념을 머릿속에 넣어두고 중첩 반복문을 이해해봅시다.
while문으로 중첩 반복문 사용해보기
중첩 반복문은 반복문 안에 또 다른 반복문을 넣어서 사용하는 것입니다. while문도 for문처럼 중첩해서 사용할 수 있습니다. 중첩 반복문은 바깥쪽 반복문이 한 번 실행될 때마다 안쪽 반복문이 처음부터 끝까지 모두 실행됩니다. 이런 구조는 구구단이나 좌표 계산처럼 2차원적인 작업을 할 때 유용하게 쓰입니다. 다음 코드를 입력해서 실행해보면 중첩 while문이 어떻게 동작하는지 금방 알 수 있을 겁니다.
i = 1
while i <= 3:
j = 1
while j <= 3:
print(f"i={i}, j={j}")
j += 1
i += 1
[실행 결과]
i=1, j=1
i=1, j=2
...생략...
i=3, j=2
i=3, j=3
결과를 보면 바깥쪽 while문의 i가 1일 때, 안쪽 while문이 j를 1부터 3까지 반복합니다. 그 다음 i가 2가 되면 다시 j가 1부터 3까지 반복하는 것을 볼 수 있습니다. 안쪽 반복문이 완전히 끝나야 바깥쪽 반복문이 다음 단계로 넘어간다는 점을 기억하세요.
while문으로 구구단 외우는 프로그램 만들기
이런 원리를 이용하면 구구단을 외우는 프로그램을 만들 수 있습니다. 프로그램의 유용함에 있어서는 의미가 크게 없지만 중첩 반복문을 이해하는 데에 초점을 맞추고 다시 코드를 작성해봅시다.
dan = 2
while dan <= 4:
num = 1
print(f"\n{dan}단:")
while num <= 5:
print(f"{dan} x {num} = {dan * num}")
num += 1
dan += 1
[실행 결과]
2단:
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
2 x 5 = 10
...생략...
4단:
4 x 1 = 4
4 x 2 = 8
4 x 3 = 12
4 x 4 = 16
4 x 5 = 20
바깥쪽 반복문이 단수(변수 dan으로 조절하고 있는 것, 2단, 3단, 4단)를 제어하고, 안쪽 반복문이 각 단에서 곱할 숫자(변수 num으로 조절하고 있는 것, 1부터 5까지)를 제어합니다. 이렇게 중첩 반복문을 사용하면 표 형태의 데이터나 2차원 패턴을 쉽게 만들 수 있습니다.
for문으로 중첩 반복문 사용해보기
이번에는 for문으로 중첩 반복문을 사용해보겠습니다. 다음은 앞에서 공부한 while문의 예제와 같지만 문법을 for문으로 바꾼 것입니다.
for i in range(1, 4):
for j in range(1, 4):
print(f"i={i}, j={j}")
[실행 결과]
i=1, j=1
i=1, j=2
...생략...
i=3, j=2
i=3, j=3
이렇게 단순히 숫자의 범위만 정해서 반복해야 할 때는 while문보다는 for문이 좀 더 코드 상 깔끔합니다. 구구단 외우는 프로그램도 마찬가지입니다.
for dan in range(2, 5):
print(f"\n{dan}단:")
for num in range(1, 6):
print(f"{dan} x {num} = {dan * num}")
[실행 결과]
2단:
2 x 1 = 2
2 x 2 = 4
...생략...
3단:
3 x 1 = 3
3 x 2 = 6
...생략...
4단:
4 x 1 = 4
4 x 2 = 8
...생략...
중첩 반복문 응용 연습하기
하지만 중첩 반복문은 이렇게 구구단이나 외우기 위한 것이 아닙니다. 조금 더 의미 있는 작업에 중첩 반복문을 사용해봅시다. 그런데 그러려면 어떻게 해야 할까요? 지금까지 배운 문법과 개념을 총동원해야 합니다. 아마 구구단 예제를 이해하고 막 넘어온 상태라 머리가 많이 복잡하겠지만 함께 천천히 생각해봅시다.
쇼핑몰 관리자가 되어 중첩 반복문 생각해보기
중첩 반복문을 사용해야 한다는 건 뭔가를 반복해서 처리해야 할 대상이 있다는 겁니다. 반복해서 처리할 수 있는 데이터는 이터러블한 데이터죠? 이처럼 반복을 생각했을 때 이터러블 데이터를 우선 떠올려보는 습관을 들이는 게 좋습니다. 예를 들어 여러분이 전자기기 쇼핑몰 관리자인데 고객이 10명이 있고 각 고객이 상품을 구매하기 위해 장바구니에 물건을 이것저것 담아 놓은 상태를 가정해봅시다. 그 상황은 딕셔너리와 리스트의 개념을 가져와서 이렇게 표현해볼 수 있습니다.

이 딕셔너리는 각 고객의 이름을 키로 하고 상품 이름을 리스트로 담고 있습니다. 그리고 딕셔너리도 리스트도 모두 반복할 수 있는, 즉, 이터러블한 데이터들입니다. 그림에 표시한 것처럼 반복할 수 있다면 각 고객이 장바구니에 담은 전체 결과를 보고하는 프로그램을 만들 수 있을 것 같네요. 만약 이런 결과물을 보고 싶다면 어떻게 코드를 작성하면 될까요?
김철수님의 주문:
- 노트북
- 마우스
- 키보드
이영희님의 주문:
- 모니터
- 스피커
박민수님의 주문:
- 태블릿
- 케이스
- 충전기
- 이어폰
중첩 반복문 구조 생각해보기
그림에서 본 대로 딕셔너리의 키를 반복하는 큰 반복문 구조를 만들고 그 안에서 고객의 상품을 반복하는 구조의 코드를 만들면 됩니다. 이런 구성을 생각하면 됩니다.
for 바깥쪽 반복문 반복하기:
딕셔너리의 키, 즉, 고객 이름 출력
for 안쪽 반복문:
리스트 값, 즉, 고객이 주문한 물건 출력
바깥쪽 반복문부터 만들어보기
우선은 바깥쪽 반복문이 어떻게 동작할지 한 번 직접 입력해서 실행해보겠습니다. 딕셔너리의 키를 이용해서 값을 출력하면 어떻게 될까요?
orders = {
"김철수": ["노트북", "마우스", "키보드"],
"이영희": ["모니터", "스피커"],
"박민수": ["태블릿", "케이스", "충전기", "이어폰"]
}
# 바깥쪽 반복문만 우선 구성하기
for key in orders:
print(f"{orders[key]}")
[실행 결과]
['노트북', '마우스', '키보드']
['모니터', '스피커']
['태블릿', '케이스', '충전기', '이어폰']
for key in orders:를 통해 orders에 있는 값을 print(f"{orders[key]}")로 출력했습니다. 실행 결과는 각 고객이 주문한 상품이 리스트로 나옵니다.
안쪽 반복문 추가해서 완성하기
이제 리스트를 그대로 출력해서 ['노트북', '마우스', '키보드']와 같이 출력하는 것만 해결하면 됩니다. 딕셔너리 문법을 공부할 때 배운 orders.items( )를 사용하면 딕셔너리에서 키와 값을 for문에 사용할 수 있으므로 이를 활용해보겠습니다.
[Note] .items( )는 (key, value) 순서쌍을 반환합니다.
orders = {
"김철수": ["노트북", "마우스", "키보드"],
"이영희": ["모니터", "스피커"],
"박민수": ["태블릿", "케이스", "충전기", "이어폰"]
}
# 중첩 반복문 사용 예시
for customer, products in orders.items():
print(f"{customer}님의 주문:")
for product in products:
print(f" - {product}")
[실행 결과]
김철수님의 주문:
- 노트북
- 마우스
- 키보드
이영희님의 주문:
- 모니터
- 스피커
박민수님의 주문:
- 태블릿
- 케이스
- 충전기
- 이어폰
이 코드를 작성하고 실행하면 아마도 ‘중첩 반복문은 상당히 어렵네’라고 느낄 것입니다. 실제로 저도 처음 중첩 반복문을 학습했을 때 머리가 깨질듯이 아팠습니다. 하지만 그런 어려움을 느끼는 이유는 지금까지 한 번도 생각해보지 않았기 때문이지 실제로 굉장히 어렵기 때문은 아닙니다. 이해가 잘 되지 않으면 수차례 반복해서 코드를 작성하여 실행해보세요.
반복문에 익숙해지기
반복문은 프로그래밍에서 정말 중요한 콘셉트입니다. 그래서 단순히 문법만 공부하고 ‘아 다 공부했다~’라고 넘어가기는 좀 아쉽습니다. 여기서는 몇 가지 실습 예제를 통해 반복문에 익숙해지겠습니다. 반복문이 충분히 나의 것이 되었다라는 느낌이 들면 중단하고 다음으로 넘어가면 됩니다.
[연습 01] 이등변 삼각형 모양 만들어보기
프로그래밍 세계에서는 고전 주제입니다. 이등변 삼각형 모양을 출력하려면 어떻게 해야 할까요? 이런 모양을 만들어야 합니다. 바로야 AI 도구들이 코드를 워낙 잘 만드므로 그냥 물어보면 코드를 만들어주겠지만 직접 여러분의 머릿속으로 계획을 세워보는 연습을 하기 바랍니다.
🔥
🔥🔥
🔥🔥🔥
🔥🔥🔥🔥
🔥🔥🔥🔥🔥
이제 코드를 작성해봅시다. 이 문제에는 정답이란 것이 없습니다. 하지만 공통 특징이 있습니다.
5회 반복해야 한다.
각 회차에서 회차 번째만큼 🔥를 출력한다.
우선 5회 반복한다라는 건 이렇게 코드를 작성할 수 있습니다.
for 5번 반복하기:
🔥를 반복 회차만큼 출력하기
그 다음은 🔥를 어떻게 반복 회차만큼 출력할지만 해결하면 됩니다. 앞에서 배운 것 중에 range( ) 함수와 문자열과 곱하기를 사용하면 문자열을 곱한만큼 복사하므로 이 둘을 잘 조합하여 사용하면 됩니다.
for firecount in range(1, 6):
print("🔥"*firecount)
[실행 결과]
🔥
🔥🔥
🔥🔥🔥
🔥🔥🔥🔥
🔥🔥🔥🔥🔥
반복문과 range( )의 조합을 절묘하게 사용하여 이등변 삼각형을 만들었습니다. 다른 아이디어가 있다면 문제를 스스로 변형해서 다른 모양을 출력해보기 바랍니다.
[연습 02] 역순 이등변 삼각형 만들어보기
이번에는 앞서 만든 이등변 삼각형을 거꾸로 뒤집어볼까요? 위에서부터 점점 줄어드는 삼각형 모양을 만들어보겠습니다.
🔥🔥🔥🔥🔥
🔥🔥🔥🔥
🔥🔥🔥
🔥🔥
🔥
앞에서 만든 프로그램을 반대로 하면 될 것 같지만 반복문을 반대로 실행하는 방법은 없습니다. 대신 숫자를 반대로 하는 방법은 있죠. 가만 생각해보면 range(1, 6)은 반복 회차마다 1, 2, 3, 4, 5를 반환하므로 이 숫자를 반대로 하는 방법만 찾으면 될 것 같습니다. 수학적 사고를 발휘할 때입니다! 정답은 각 회차마다 6 - firecount 값을 계산하면 됩니다. 첫 번째 회차(1)에서는 5개, 마지막 회차(5)에서는 1개가 출력되겠죠. 코드는 다음과 같습니다.
for firecount in range(1, 6):
print("🔥" * (6 - firecount))
[실행 결과]
🔥🔥🔥🔥🔥
🔥🔥🔥🔥
🔥🔥🔥
🔥🔥
🔥
[연습 03] 숫자 카운트다운 만들기
로켓을 발사할 때 "10, 9, 8, 7... 발사!" 하는 카운트다운을 본 적 있죠? 이번에는 사용자가 원하는 숫자부터 카운트다운하는 프로그램을 만들어봅시다. 예를 들어 5를 입력하면 다음과 같이 출력하는 겁니다.
5
4
3
2
1
발사! 🚀
여기서 중요한 건 사용자에게 숫자를 입력받는 겁니다. 그리고 거꾸로 숫자를 출력하는 것이죠. 숫자를 거꾸로 출력하는 건 앞에서도 해봤으니 그렇게 어렵진 않습니다. 숫자를 입력받는 건 input( ) 함수를 사용하면 되고요. 공부한지 좀 됐으니 다시 설명하자면 input( ) 함수는 키보드로 어떤 값을 입력 받아 [Enter]를 누를 때까지 정지합니다. 그리고 키보드로 입력한 값은 input( ) 함수를 대신해서 남게 되죠. 다만 input( ) 함수를 실행한 다음 입력 받는 값은 숫자를 입력해도 모두 문자열로 인식합니다. 그래서 input( ) 함수를 다시 int( ) 함수로 감싸 숫자로 변환한 것입니다.
[Note] 만약 int( ) 함수를 감싸지 않으면 range( ) 함수에 전달해야 하는 값이 숫자가 아닌 문자열이 되어 range(0, start)에서 오류가 발생합니다.
start = int(input("몇부터 카운트다운할까요? "))
for count in range(0, start):
print(start - count)
print("발사! 🚀")
[실행 결과] (5를 입력했다고 가정)
몇부터 카운트다운할까요? 5
5
4
3
2
1
발사! 🚀
[연습 04] 평균 점수 계산기 만들기
학생들의 시험 점수를 입력받아서 평균을 계산하는 프로그램을 만들어봅시다. 몇 명의 점수를 입력받을지도 사용자가 정할 수 있게 만들어보겠습니다. 예를 들어 학생이 4명이고 점수가 85, 90, 78, 92라면 다음과 같이 프로그램을 실행하면 됩니다.
몇 명의 점수를 입력하시겠습니까? 4
1번 학생 점수: 85
2번 학생 점수: 90
3번 학생 점수: 78
4번 학생 점수: 92
총점: 345점
평균: 86.25점
프로그램의 진행 방식을 보면 결국은 [연습 03] 숫자 카운트다운 만들기의 input( )을 조금 더 써보는 연습 문제라는 걸 알 수 있습니다. 처음의 몇 명의 점수를 입력할지를 유도하는 input( )은 한 번 출력하지만 이후 학생 점수를 받기 위한 input( )은 사용자가 입력한 수만큼 반복해야 합니다. 코드는 다음과 같이 작성합니다.
# 학생 수 입력받기
count = int(input("몇 명의 점수를 입력하시겠습니까? "))
# 총점을 저장할 변수
total = 0
# 각 학생의 점수 입력받기
for i in range(1, count + 1):
score = int(input(f"{i}번 학생 점수: "))
total = total + score
# 평균 계산
average = total / count
# 결과 출력
print(f"총점: {total}점")
print(f"평균: {average}점")
