! 앞에서는 조건에 따라 실행할 코드를 결정하는
if문, 조건이 참인 동안 반복하는while문에 대해서 알아보았다.
for문은 리스트, 튜플, 문자열처럼 여러 개의 값을 가진 자료에서 값을 하나씩 꺼내 반복해서 처리할 때 사용한다.while문보다 for문을 사용하는 것이 편리하다.for문의 기본 구조는 다음과 같다.
for 변수 in 반복_가능한_자료:
실행할 문장
예를 들어 다음 리스트가 있다고 하자.
numbers = [1, 2, 3]
다음과 같이 for문을 사용할 수 있다.
for number in numbers:
print(number)
1
2
3
위 코드는 다음 순서로 실행된다.
numbers = [1, 2, 3]
첫 번째 반복
number = 1
print(number)
↓
1 출력
두 번째 반복
number = 2
print(number)
↓
2 출력
세 번째 반복
number = 3
print(number)
↓
3 출력
실행 흐름을 간단하게 표현하면 다음과 같다.
[1, 2, 3]
│
├─ 1 → number → 코드 실행
│
├─ 2 → number → 코드 실행
│
└─ 3 → number → 코드 실행
↓
종료
while문처럼 직접 변수 값을
+1할 필요가 없다는 것이 특징이다.
문자열이 들어 있는 리스트를 반복해 보자.
test_list = ['one', 'two', 'three']
for i in test_list:
print(i)
one
two
three
첫 번째 반복에서는
i = 'one'
이 된다.
따라서
print(i)
의 결과는
one
이다.
두 번째 반복에서는
i = 'two'
세 번째 반복에서는
i = 'three'
이 된다.
즉, for문의 변수에는 반복할 자료의 값이 하나씩 자동으로 대입된다.
'one' → i
'two' → i
'three' → i
for문은 리스트뿐만 아니라 튜플, 문자열 등 반복 가능한 자료형에서도 사용할 수 있다.
word = "python"
for char in word:
print(char)
p
y
t
h
o
n
문자열
"python"에서 문자를 하나씩 꺼내char에 대입하는 것이다.
p → char
y → char
t → char
h → char
o → char
n → char
numbers = (10, 20, 30)
for number in numbers:
print(number)
10
20
30
리스트 안에 튜플이 들어 있는 경우도 있다.
a = [(1, 2), (3, 4), (5, 6)]
다음과 같이 사용할 수 있다.
for first, last in a:
print(first + last)
3
7
11
첫 번째 요소는 다음과 같다.
(1, 2)
이를
first, last
에 대입한다.
first = 1
last = 2
따라서
1 + 2 = 3
이 출력된다.
두 번째 반복에서는
first = 3
last = 4
↓
3 + 4 = 7
세 번째 반복에서는
first = 5
last = 6
↓
5 + 6 = 11
이 된다.
이처럼 튜플의 값을 여러 변수에 한 번에 나누어 받는 것을 언패킹(unpacking)이라고 한다.
학생들의 시험 점수가 다음과 같다고 하자.
marks = [90, 25, 67, 45, 80]
으로 판단해 보자.
marks = [90, 25, 67, 45, 80]
number = 0
for mark in marks:
number += 1
if mark >= 60:
print(f"{number}번 학생은 합격입니다.")
else:
print(f"{number}번 학생은 불합격입니다.")
1번 학생은 합격입니다.
2번 학생은 불합격입니다.
3번 학생은 합격입니다.
4번 학생은 불합격입니다.
5번 학생은 합격입니다.
첫 번째 반복에서는
mark = 90
number = 1
이 된다.
조건을 확인하면
90 >= 60
↓
True
따라서 합격이다.
두 번째 반복에서는
mark = 25
number = 2
이고
25 >= 60
↓
False
이므로 불합격이다.
이처럼 실제 프로그램에서는
for문과if문을 함께 사용하는 경우가 매우 많다.
for 값 in 데이터:
if 조건:
실행문
else:
실행문
while문에서 배운
continue를 for문에서도 사용할 수 있다.
continue를 만나면 현재 반복의 남은 코드를 실행하지 않고 다음 반복으로 이동한다.
60점 이상인 학생에게만 합격 메시지를 출력해 보자.
marks = [90, 25, 67, 45, 80]
number = 0
for mark in marks:
number += 1
if mark < 60:
continue
print(f"{number}번 학생 축하합니다. 합격입니다.")
1번 학생 축하합니다. 합격입니다.
3번 학생 축하합니다. 합격입니다.
5번 학생 축하합니다. 합격입니다.
2번 학생의 점수는
25점이다.
if mark < 60:
조건을 확인하면
25 < 60
↓
True
따라서
continue
가 실행된다.
그러면 아래의
print(...)
은 실행하지 않는다.
25점
↓
60점 미만
↓
continue
↓
print 건너뜀
↓
다음 학생
정리하면
continue
→ 현재 반복의 나머지 코드 건너뛰기
→ 다음 반복 시작
이다.
for문은
range()함수와 매우 자주 함께 사용한다.
range()는 연속된 숫자를 만들어 반복할 때 유용하다.
range(10)
은 다음 숫자 범위를 의미한다.
0
1
2
3
4
5
6
7
8
9
중요한 점은 10이 포함되지 않는다는 것이다.
range(10)
↓
0 이상 10 미만
리스트로 확인하면 이해하기 쉽다.
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
시작 숫자를 지정할 수도 있다.
range(1, 11)
결과는
1
2
3
4
5
6
7
8
9
10
이다.
기본 형태는 다음과 같다.
range(시작, 끝)
시작 → 포함
끝 → 포함하지 않음
따라서
range(1, 11)
은
1 이상 11 미만
↓
1 ~ 10
이다.
세 번째 값을 지정하면 숫자가 증가하는 간격을 설정할 수 있다.
>>> list(range(1, 10, 2))
[1, 3, 5, 7, 9]
1부터 시작
+2
↓
1 → 3 → 5 → 7 → 9
짝수만 만들 수도 있다.
>>> list(range(2, 11, 2))
[2, 4, 6, 8, 10]
range(끝)
range(시작, 끝)
range(시작, 끝, 증가값)
1부터 5까지 출력해 보자.
for i in range(1, 6):
print(i)
1
2
3
4
5
while문으로 작성하면 다음과 비슷하다.
i = 1
while i <= 5:
print(i)
i += 1
for문에서는 변수 증가를 직접 작성하지 않아도 된다.
while
i = 1
↓
조건 검사
↓
print
↓
i += 1
반면
for
range(1, 6)
↓
1
2
3
4
5
자동 반복
for와range()를 사용해서 1부터 10까지의 합을 구해 보자.
total = 0
for i in range(1, 11):
total += i
print(total)
55
처음에는
total = 0
이다.
첫 번째 반복
total = 0 + 1
↓
1
두 번째 반복
total = 1 + 2
↓
3
세 번째 반복
total = 3 + 3
↓
6
이러한 과정을 계속 반복하면
1 + 2 + 3 + 4 + 5
+ 6 + 7 + 8 + 9 + 10
=
55
가 된다.
누적 계산을 할 때는 다음과 같은 구조를 자주 사용한다.
total = 0
for 값 in 데이터:
total += 값
리스트의 인덱스 번호가 필요한 경우
range()와len()을 함께 사용할 수도 있다.
marks = [90, 25, 67, 45, 80]
for number in range(len(marks)):
print(number)
0
1
2
3
4
왜냐하면
len(marks)
의 결과는
5
이고
range(5)
는
0, 1, 2, 3, 4
이기 때문이다.
따라서
marks[number]
를 사용하면 리스트의 값을 차례대로 가져올 수 있다.
marks[0] → 90
marks[1] → 25
marks[2] → 67
marks[3] → 45
marks[4] → 80
for number in range(len(marks)):
if marks[number] >= 60:
print(f"{number + 1}번 학생은 합격입니다.")
for문 안에 또 다른 for문을 사용할 수 있다.
이를 중첩 for문이라고 한다.
for 변수1 in 데이터1:
for 변수2 in 데이터2:
실행문
바깥쪽 for문이 한 번 실행될 때마다 안쪽 for문이 처음부터 끝까지 실행된다.
바깥 반복 1
│
├─ 안쪽 반복 1
├─ 안쪽 반복 2
└─ 안쪽 반복 3
바깥 반복 2
│
├─ 안쪽 반복 1
├─ 안쪽 반복 2
└─ 안쪽 반복 3
중첩 for문의 대표적인 예제가 구구단이다.
for dan in range(2, 10):
for number in range(1, 10):
print(dan * number, end=" ")
print()
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
for dan in range(2, 10):
dan에는
2
3
4
5
6
7
8
9
가 차례대로 들어간다.
for number in range(1, 10):
number에는
1 ~ 9
가 차례대로 들어간다.
따라서
dan = 2일 때
2 × 1
2 × 2
2 × 3
...
2 × 9
를 모두 계산한다.
그다음
dan = 3
이 되면서 다시
3 × 1
3 × 2
...
3 × 9
를 계산한다.
기본적으로
print()는 값을 출력한 뒤 줄을 바꾼다.
print(1)
print(2)
1
2
하지만
print(1, end=" ")
print(2, end=" ")
처럼 사용하면
1 2
처럼 같은 줄에 출력할 수 있다.
아직
print()의 자세한 옵션을 배우지 않았다면end=" "는 출력 후 줄을 바꾸지 않고 공백을 넣는다 정도로 이해하면 된다.
for문을 이용해서 새로운 리스트를 만드는 작업은 매우 자주 사용된다.
예를 들어 다음 리스트의 모든 숫자에 3을 곱한다고 해 보자.
a = [1, 2, 3, 4]
result = []
for number in a:
result.append(number * 3)
print(result)
[3, 6, 9, 12]
파이썬에서는 이것을 더 간단하게 표현할 수 있다.
이를 리스트 컴프리헨션(List Comprehension)이라고 한다.
a = [1, 2, 3, 4]
result = [number * 3 for number in a]
print(result)
[3, 6, 9, 12]
기본 형태는 다음과 같다.
[표현식 for 변수 in 반복_가능한_자료]
예를 들어
[number * 3 for number in a]
는 다음과 같이 읽으면 된다.
a에서 number를 하나씩 꺼내서
↓
number * 3을 계산하고
↓
새로운 리스트에 저장
일반 for문과 비교하면 다음과 같다.
result = []
for number in a:
result.append(number * 3)
result = [number * 3 for number in a]
결과는 같다.
조건에 맞는 값만 새로운 리스트에 넣을 수도 있다.
예를 들어 짝수에만 3을 곱해 보자.
a = [1, 2, 3, 4]
result = [
number * 3
for number in a
if number % 2 == 0
]
print(result)
[6, 12]
number가1일 때
1 % 2 == 0
↓
False
이므로 제외한다.
number가 2일 때
2 % 2 == 0
↓
True
이므로
2 × 3 = 6
을 리스트에 넣는다.
결국
2 → 6
4 → 12
만 남는다.
기본 구조는 다음과 같다.
[
표현식
for 변수 in 반복_자료
if 조건
]
리스트 컴프리헨션 안에서도 여러 개의 for문을 사용할 수 있다.
예를 들어 구구단 결과를 모두 리스트에 저장해 보자.
result = [
x * y
for x in range(2, 10)
for y in range(1, 10)
]
이 코드는 다음과 비슷한 의미이다.
result = []
for x in range(2, 10):
for y in range(1, 10):
result.append(x * y)
처음 리스트 컴프리헨션을 공부할 때 너무 복잡하게 느껴진다면 일반 for문으로 먼저 작성한 뒤 리스트 컴프리헨션으로 바꿔 보는 것이 이해하기 쉽다.
while문과 마찬가지로for문에서도break를 사용할 수 있다.
break를 만나면 for문을 즉시 종료한다.
for i in range(10):
if i == 5:
break
print(i)
0
1
2
3
4
i에는 다음 값이 들어간다.
0 → 1 → 2 → 3 → 4 → 5 → ...
i가 5가 되면
if i == 5:
가 참이 된다.
따라서
break
가 실행된다.
i = 5
↓
조건 True
↓
break
↓
for문 종료
그래서 5는 출력되지 않는다.
정리하면
break
→ 반복할 데이터가 아직 남아 있어도 반복문 종료
이다.
파이썬에서는 for문에도
else를 붙일 수 있다.
for 변수 in 데이터:
실행문
else:
실행문
else를 실행한다.break를 만나 반복문을 빠져나가면 else는 실행하지 않는다.for i in range(5):
print(i)
else:
print("for문이 정상적으로 끝났습니다.")
0
1
2
3
4
for문이 정상적으로 끝났습니다.
0 ~ 4까지 모든 반복을 끝냈다.break를 만나지 않았다.else가 실행된다.for i in range(5):
if i == 3:
break
print(i)
else:
print("for문이 정상적으로 끝났습니다.")
0
1
2
i == 3일 때 break를 만나 반복문이 종료된다.else는 실행되지 않는다.정리하면 다음과 같다.
| for문의 종료 방법 | else 실행 |
|---|---|
| 모든 반복 완료 | O |
break로 종료 | X |
대표적으로 어떤 값을 찾는 작업에서 사용할 수 있다.
numbers = [1, 3, 5, 7]
target = 4
for number in numbers:
if number == target:
print("찾았습니다.")
break
else:
print("찾지 못했습니다.")
찾지 못했습니다.
만약 값을 발견하면
break
가 실행된다.
그러면 else는 실행되지 않는다.
즉,
for-else는 반복문이 break 없이 끝났는지 확인할 때 유용하다.
리스트를 반복하면서 인덱스 번호와 값이 모두 필요한 경우가 있다.
이때 enumerate()를 사용하면 편리하다.
fruits = ['apple', 'banana', 'orange']
for index, fruit in enumerate(fruits):
print(index, fruit)
0 apple
1 banana
2 orange
일반적인 for문에서는 값만 가져온다.
for fruit in fruits:
apple
banana
orange
enumerate()를 사용하면
for index, fruit in enumerate(fruits):
다음 두 값을 동시에 얻을 수 있다.
0 → apple
1 → banana
2 → orange
즉,
인덱스 + 값
을 함께 사용할 수 있다.
기본 인덱스는
0부터 시작한다.
enumerate(fruits)
0 apple
1 banana
2 orange
하지만 다음처럼 시작 번호를 지정할 수 있다.
for number, fruit in enumerate(fruits, 1):
print(number, fruit)
1 apple
2 banana
3 orange
학생 번호처럼
1번부터 시작해야 하는 경우 매우 편리하다.
marks = [90, 25, 67, 45, 80]
for number, mark in enumerate(marks, 1):
print(f"{number}번 학생: {mark}점")
앞에서 사용했던
number = 0
for mark in marks:
number += 1
을 더 간단하게 만들 수 있는 것이다.
enumerate(반복할_자료)
→ 인덱스 + 값
두 개 이상의 리스트를 같은 위치끼리 묶어서 동시에 반복하고 싶다면
zip()을 사용할 수 있다.
names = ['홍길동', '김철수', '이영희']
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(name, score)
홍길동 85
김철수 92
이영희 78
두 리스트가 다음과 같다고 하자.
names
홍길동
김철수
이영희
scores
85
92
78
zip()은 같은 위치의 값을 묶는다.
홍길동 ↔ 85
김철수 ↔ 92
이영희 ↔ 78
따라서
for name, score in zip(names, scores):
첫 번째 반복에서는
name = '홍길동'
score = 85
두 번째 반복에서는
name = '김철수'
score = 92
가 된다.
zip()은 두 개만 사용할 수 있는 것이 아니다.
names = ['홍길동', '김철수', '이영희']
korean = [85, 92, 78]
english = [90, 88, 95]
for name, kor, eng in zip(names, korean, english):
print(name, kor, eng)
홍길동 85 90
김철수 92 88
이영희 78 95
구조는 다음과 같다.
홍길동 ↔ 85 ↔ 90
김철수 ↔ 92 ↔ 88
이영희 ↔ 78 ↔ 95
zip()은 가장 짧은 자료의 길이까지만 반복한다.
a = [1, 2, 3]
b = ['A', 'B']
for x, y in zip(a, b):
print(x, y)
1 A
2 B
b에는 값이 2개뿐이므로 반복도 2번만 수행된다.이 부분은 여러 리스트를
zip()으로 묶을 때 기억해 두는 것이 좋다.
enumerate()와zip()을 같이 사용할 수도 있다.
names = ['홍길동', '김철수', '이영희']
scores = [85, 92, 78]
for number, (name, score) in enumerate(zip(names, scores), 1):
print(f"{number}번 {name}: {score}점")
1번 홍길동: 85점
2번 김철수: 92점
3번 이영희: 78점
각각의 역할은 다음과 같다.
zip()
→ 이름과 점수를 묶음
enumerate()
→ 번호를 붙임
결국
1 + 홍길동 + 85
2 + 김철수 + 92
3 + 이영희 + 78
을 한 번에 처리할 수 있다.
두 문장 모두 반복문이지만 사용하는 상황에 차이가 있다.
while 조건:
실행문
for 변수 in 데이터:
실행문
| 구분 | while | for |
|---|---|---|
| 기준 | 조건 | 반복 가능한 자료 |
| 종료 | 조건이 False | 모든 값 사용 |
| 횟수 | 명확하지 않아도 됨 | 비교적 명확 |
| 변수 증가 | 직접 하는 경우 많음 | 자동 |
| 대표 사용 | 특정 조건까지 반복 | 리스트 순회 |
예를 들어 1부터 5까지 출력한다면
for가 간단하다.
for i in range(1, 6):
print(i)
사용자가
"exit"을 입력할 때까지 계속 입력받는다면while이 자연스럽다.
while True:
command = input("명령: ")
if command == "exit":
break
무조건 어느 하나가 더 좋은 것은 아니며 상황에 맞게 선택하면 된다.
for문에서도 두 명령어의 차이를 확실하게 기억하자.
break
반복문 자체 종료
continue
현재 반복만 건너뜀
↓
다음 반복 계속
| 명령어 | 동작 |
|---|---|
break | 반복문 종료 |
continue | 현재 반복 건너뛰기 |
range(1, 10)
은
1 ~ 10
이 아니다.
정확하게는
1 ~ 9
이다.
끝 숫자는 포함하지 않는다.
range(1, 11)
을 사용해야 1 ~ 10이 된다.
잘못된 코드
for i in range(5):
print(i)
print("반복")
❌ 들여쓰기 깊이가 맞지 않는다.
올바른 코드
for i in range(5):
print(i)
print("반복")
다음과 같은 코드는 일반적으로 필요하지 않다.
for i in range(5):
print(i)
i += 1
for가 다음 반복에서 i에 새로운 값을 자동으로 넣기 때문이다.
range(5)
↓
0
1
2
3
4
↓
자동으로 i에 대입
break
→ 반복 종료
continue
→ 현재 반복만 건너뜀
다음과 같이 너무 많은 조건과 반복을 한 줄에 넣으면 읽기 어려워질 수 있다.
리스트 컴프리헨션은 코드가 간단할 때 사용하는 것이 좋다.
복잡하다면
result = []
for value in data:
if 조건:
result.append(value)
처럼 일반 for문으로 작성하는 편이 읽기 쉽다.
다음 코드를 살펴보자.
numbers = [1, 2, 3, 4, 5]
for number in numbers:
if number == 2:
continue
if number == 5:
break
print(number)
number == 2 → False
number == 5 → False
↓
1 출력
number == 2 → True
↓
continue
↓
print() 건너뜀
3 출력
4 출력
number == 5 → True
↓
break
↓
for문 종료
1
3
4
이 예제를 이해하면
for,if,continue,break의 관계를 한 번에 이해할 수 있다.
이번 장에서 가장 중요한 내용을 정리하면 다음과 같다.
for 변수 in 반복_가능한_자료:
실행문
데이터에서 값을 하나 꺼냄
↓
변수에 저장
↓
코드 실행
↓
다음 값
for number in [1, 2, 3]:
print(number)
for char in "python":
print(char)
range(5)
0 ~ 4
range(1, 6)
1 ~ 5
끝 숫자는 포함하지 않는다.
continue
→ 현재 반복을 건너뛰고 다음 반복으로 이동
break
→ 반복문 자체 종료
for i in range(2, 10):
for j in range(1, 10):
print(i * j)
→ 바깥쪽 반복 한 번마다 안쪽 반복을 처음부터 끝까지 수행
[number * 3 for number in numbers]
→ for문을 이용해서 새로운 리스트 생성
[
number * 3
for number in numbers
if number % 2 == 0
]
for value in data:
...
else:
...
끝까지 반복 → else 실행
break 실행 → else 실행 X
for index, value in enumerate(data):
인덱스 + 값
을 동시에 가져온다.
for a, b in zip(list1, list2):
→ 여러 자료의 같은 위치에 있는 값을 함께 가져온다.
! for문에서 반드시 기억해야 할 핵심
for문은 반복 가능한 자료에서 값을 하나씩 꺼내면서 코드를 반복한다.
데이터 │ ├─ 첫 번째 값 → 변수 → 코드 실행 ├─ 두 번째 값 → 변수 → 코드 실행 ├─ 세 번째 값 → 변수 → 코드 실행 │ └─ 마지막 값 → 변수 → 코드 실행 ↓ 종료가장 기본적인 형태부터 확실하게 기억하자.
for 변수 in 반복_자료: 실행문숫자를 일정한 범위만큼 반복하고 싶다면
range()를 사용한다.for i in range(1, 6): print(i)이때
range(1, 6) → 1, 2, 3, 4, 5처럼 끝 숫자는 포함하지 않는다.
반복의 흐름을 변경할 때는
continue → 현재 반복 건너뛰기 break → 반복문 종료를 사용한다.
그리고 파이썬에서 자주 사용하는 반복 도구들도 기억해 두자.
range() → 연속된 숫자로 반복 enumerate() → 번호 + 값 zip() → 여러 자료를 동시에 반복 리스트 컴프리헨션 → 반복 결과를 새로운 리스트로 간단하게 생성마지막으로
while문과for문을 다음과 같이 구분하면 쉽다.while → "언제까지 반복할까?" → 조건 중심 for → "무엇을 하나씩 반복할까?" → 데이터 중심for문을 볼 때는 항상
1. 어떤 자료를 반복하는가? 2. 각 반복마다 변수에 어떤 값이 들어가는가? 3. break 또는 continue가 있는가?이 세 가지를 확인하면 대부분의 for문 실행 과정을 쉽게 따라갈 수 있다.