Python for 문이란?
Python의 for 문은 반복 가능한 객체(iterable) 를 하나씩 순회할 때 사용한다.
C, Java처럼 “초기값; 조건; 증감” 형태를 직접 쓰는 방식이 아니라, 컬렉션이나 범위를 꺼내며 순회하는 방식에 더 가깝다.
가장 기본 형태는 다음과 같다.
for item in iterable: |
여기서 iterable 로 사용할 수 있는 대표 자료형은 다음과 같다.
listtuplestringsetdictionaryrange()
가장 기본적인 for 문
fruits = ["apple", "banana", "orange"] |
실행 결과:
apple |
이 코드는 fruits 안의 값을 하나씩 fruit 변수에 넣으면서 반복한다.
range() 와 함께 사용하기
숫자 범위를 반복하고 싶을 때는 range() 를 많이 사용한다.
1부터 4까지 반복
for i in range(1, 5): |
실행 결과:
1 |
range(start, stop) 에서 stop 값은 포함되지 않는다.
0부터 시작
for i in range(5): |
실행 결과:
0 |
증가폭 지정
for i in range(0, 10, 2): |
실행 결과:
0 |
문자열 순회
문자열도 iterable 이기 때문에 한 글자씩 순회할 수 있다.
text = "python" |
실행 결과:
p |
list 와 함께 사용하는 방법
list 는 가장 흔하게 for 와 함께 사용하는 자료구조다.
numbers = [10, 20, 30, 40] |
합계 구하기
numbers = [10, 20, 30, 40] |
실행 결과:
100 |
조건문과 함께 사용
numbers = [1, 2, 3, 4, 5, 6] |
실행 결과:
2 |
tuple 과 함께 사용하는 방법
tuple 도 list 와 거의 같은 방식으로 순회할 수 있다.
colors = ("red", "green", "blue") |
tuple 은 수정이 불가능하다는 점만 다르고, for 순회 방식은 거의 같다.
set 과 함께 사용하는 방법
set 은 중복을 허용하지 않는 자료구조 다.for 문으로 순회할 수 있지만, 중요한 특징이 하나 있다.
- 순서가 보장되지 않는다
numbers = {1, 2, 3, 4, 5} |
출력 순서는 실행 환경에 따라 달라질 수 있다.
set 의 중복 제거 활용
data = [1, 1, 2, 2, 3, 4, 4, 5] |
이 방식은 중복 제거 후 순회할 때 간단하게 쓸 수 있다.
정렬해서 순회하고 싶다면
set 은 순서가 없으므로, 정렬된 순서가 필요하면 sorted() 와 같이 사용한다.
numbers = {5, 3, 1, 4, 2} |
실행 결과:
1 |
즉 set 은 중복 제거용, sorted(set_data) 는 중복 제거 후 정렬 순회용 으로 이해하면 편하다.
dictionary 와 함께 사용하는 방법
dictionary 는 Python에서 매우 자주 쓰이는 자료구조다.for 문과 함께 사용할 때는 무엇을 순회하는지 구분하는 것이 중요하다.
1. key 만 순회
기본적으로 for key in dict 형태는 key 를 순회한다.
user = { |
실행 결과:
name |
2. value 꺼내기
user = { |
실행 결과:
Alice |
3. keys() 사용
for key in user.keys(): |
for key in user: 와 거의 같은 의미다.
4. values() 사용
for value in user.values(): |
실행 결과:
Alice |
5. items() 사용
가장 많이 쓰는 방식 중 하나다. key 와 value 를 같이 꺼낼 수 있다.
for key, value in user.items(): |
실행 결과:
name Alice |
실무에서는 dict 순회 시 items() 를 가장 많이 사용한다고 생각해도 크게 틀리지 않는다.
enumerate() 와 함께 사용하기
반복하면서 인덱스도 같이 필요할 때는 enumerate() 를 사용한다.
fruits = ["apple", "banana", "orange"] |
실행 결과:
0 apple |
1부터 시작하고 싶다면
for index, fruit in enumerate(fruits, start=1): |
실행 결과:
1 apple |
range(len(list)) 보다 enumerate() 가 더 Python 답고 읽기 쉽다.
zip() 과 함께 사용하기
여러 개의 iterable 을 동시에 순회할 때는 zip() 을 사용한다.
names = ["Alice", "Bob", "Charlie"] |
실행 결과:
Alice 90 |
이 방식은 관련 있는 데이터를 같이 순회할 때 매우 편리하다.
for 문과 시간복잡도
Python에서 for 문을 사용할 때는 문법만 아는 것보다, 반복 횟수가 얼마나 되는지 같이 보는 것이 중요하다.
가장 기본적인 기준은 다음과 같다.
- 원소를
n개 가진 리스트를 한 번 순회하면 보통O(n) - 이중 반복문으로
n x n형태를 돌면 보통O(n^2) - 반복문 안에서 어떤 연산을 하느냐에 따라 실제 비용이 더 커질 수 있음
즉 for 문 자체보다, 몇 번 반복하는지 + 반복 안에서 무엇을 하는지 를 같이 봐야 한다.
가장 기본적인 O(n)
numbers = [1, 2, 3, 4, 5] |
리스트 길이가 n 이라면 이 코드는 원소를 한 번씩만 보기 때문에 보통 O(n) 이다.
중첩 반복문의 O(n^2)
numbers = [1, 2, 3, 4, 5] |
바깥쪽이 n 번, 안쪽도 n 번 돌기 때문에 보통 O(n^2) 이다.
이런 구조는 데이터가 커질수록 성능 차이가 급격히 커진다.
자료구조별 순회 시간복잡도
자주 쓰는 자료구조를 순회할 때의 기본 시간복잡도는 보통 다음처럼 정리할 수 있다.
| 자료구조 | 순회 예시 | 시간복잡도 |
|---|---|---|
list |
for x in my_list |
O(n) |
tuple |
for x in my_tuple |
O(n) |
string |
for ch in text |
O(n) |
set |
for x in my_set |
O(n) |
dict key 순회 |
for k in my_dict |
O(n) |
dict value 순회 |
for v in my_dict.values() |
O(n) |
dict item 순회 |
for k, v in my_dict.items() |
O(n) |
즉 대부분 “전체를 한 번씩 본다” 는 점에서는 O(n) 이다.
하지만 중요한 차이는 탐색 연산 에서 나온다.
in 연산과 시간복잡도
for 문 안에서 in 연산을 같이 쓰면 시간복잡도가 달라질 수 있다.
list 에서 in
numbers = [1, 2, 3, 4, 5] |
리스트는 처음부터 순차적으로 찾기 때문에 보통 O(n) 이다.
set 에서 in
numbers = {1, 2, 3, 4, 5} |
set 은 해시 기반이라 평균적으로 O(1) 에 가깝다.
dict 에서 in
user = {"name": "Alice", "age": 20} |
dict 도 해시 기반이라 key 조회는 평균적으로 O(1) 에 가깝다.
즉 단순 순회는 다들 O(n) 이지만:
- membership check 는
list보다set/dict가 훨씬 유리한 경우가 많다
for 문 안에서 list 검색을 하면 느려질 수 있다
초보자 코드에서 자주 나오는 패턴이다.
items = [1, 2, 3, 4, 5] |
겉으로 보기엔 단순해 보이지만:
- 바깥 반복:
O(n) item in targets: 리스트 탐색O(m)
이므로 전체는 대략 O(n * m) 이 된다.
만약 targets 가 크다면 비효율적일 수 있다.
이럴 때는 set 으로 바꾸는 것이 좋다.
items = [1, 2, 3, 4, 5] |
이 경우 평균적으로:
- 바깥 반복:
O(n) item in targets:O(1)
이므로 전체는 대략 O(n) 에 가까워진다.
이게 set 을 자주 쓰는 대표 이유 중 하나다.
중첩 for 문
for 문 안에 또 다른 for 문을 넣을 수도 있다.
for i in range(2): |
실행 결과:
0 0 |
2차원 리스트를 순회할 때도 자주 사용한다.
matrix = [ |
2차원 리스트에서 행이 r 개이고 열이 c 개라면, 이 코드는 보통 O(r * c) 로 볼 수 있다.
break, continue, else
break
반복을 즉시 종료한다.
for i in range(10): |
continue
현재 반복만 건너뛰고 다음 반복으로 넘어간다.
for i in range(5): |
for ... else
Python의 for 문은 else 와 함께 사용할 수 있다.
반복이 break 없이 정상 종료되면 else 가 실행된다.
numbers = [1, 3, 5, 7] |
실행 결과:
없다 |
list, set, dict 와 함께 쓰는 실전 예제
1. 리스트에서 짝수만 추출
numbers = [1, 2, 3, 4, 5, 6] |
2. 중복 제거 후 출력
names = ["Tom", "Jane", "Tom", "Alice", "Jane"] |
이 코드는 보통 다음 비용으로 볼 수 있다.
set(names):O(n)평균for name in ...:O(n)
즉 전체적으로는 대략 O(n) 이다.
정렬까지 하고 싶다면:
for name in sorted(set(names)): |
이 경우는 정렬이 들어가므로:
set(names):O(n)sorted(...):O(n log n)- 순회:
O(n)
전체는 보통 O(n log n) 으로 본다.
3. 딕셔너리 값 합계 구하기
scores = { |
이 코드는 값을 한 번씩만 보기 때문에 O(n) 이다.
4. 딕셔너리에서 특정 조건 찾기
users = { |
이것도 딕셔너리 항목을 한 번씩 보기 때문에 기본적으로 O(n) 이다.
컴프리헨션과 비교
for 문은 가장 기본적인 반복 방식이고, Python에서는 이를 더 짧게 쓰는 컴프리헨션 도 자주 사용한다.
예를 들어:
numbers = [1, 2, 3, 4, 5] |
위 코드는 리스트 컴프리헨션으로 더 짧게 쓸 수 있다.
numbers = [1, 2, 3, 4, 5] |
하지만 처음 학습할 때는 for 문 기본 구조를 먼저 익히는 것이 중요하다.
복잡한 로직은 여전히 일반 for 문이 더 읽기 쉬운 경우가 많다.
for 문을 한 줄처럼 표현하는 방법
Python에서는 일반 for 문 외에도, 반복 결과를 한 줄로 만드는 comprehension 문법을 자주 사용한다.
처음 보면 for 문을 거꾸로 쓴 것처럼 보일 수 있지만, 실제 문법은 “표현식이 먼저, for 가 나중” 이다.
기본 형태는 다음과 같다.
[expression for item in iterable] |
즉 “무엇을 만들 것인가” 가 앞에 오고, “어떻게 순회할 것인가” 가 뒤에 온다.
이 문법은 기존 for 문보다 짧고 간결해서, 단순 변환이나 필터링 작업에서 특히 많이 쓰인다.
이 문법은 보통 다음 네 가지로 나뉜다.
- list comprehension
- set comprehension
- dictionary comprehension
- generator expression
1. List Comprehension
리스트를 한 줄로 만들 때 사용한다.
numbers = [1, 2, 3, 4, 5] |
실행 결과:
[2, 4, 6, 8, 10] |
조건도 붙일 수 있다.
evens = [x for x in numbers if x % 2 == 0] |
실행 결과:
[2, 4] |
2. Set Comprehension
중복 없는 set 을 한 줄로 만들 때 사용한다.
numbers = [1, 1, 2, 2, 3, 4] |
실행 결과:
{1, 2, 3, 4} |
값을 변형할 수도 있다.
squares = {x * x for x in [1, 2, 3, 4]} |
주의할 점은 set 이므로 순서를 보장하지 않는다는 점이다.
3. Dictionary Comprehension
dict 를 한 줄로 만들 때 사용한다.
numbers = [1, 2, 3, 4] |
실행 결과:
{1: 1, 2: 4, 3: 9, 4: 16} |
기존 딕셔너리에서 조건에 맞는 항목만 다시 만들 수도 있다.
scores = { |
실행 결과:
{'math': 90, 'science': 95} |
4. Generator Expression
리스트처럼 보이지만 [] 대신 () 를 사용하면 generator 가 된다.
numbers = (x * 2 for x in range(5)) |
이건 바로 리스트가 만들어지는 것이 아니라, 필요할 때 값을 하나씩 꺼내는 generator 객체다.
for value in numbers: |
실행 결과:
0 |
comprehension 문법 요약
리스트
[x for x in iterable] |
리스트 + 조건
[x for x in iterable if condition] |
셋
{x for x in iterable} |
딕셔너리
{k: v for k, v in iterable} |
제너레이터
(x for x in iterable) |
일반 for 문과 comprehension 의 차이
일반 for 문:
result = [] |
comprehension:
result = [x * 2 for x in range(5)] |
보통 comprehension 이 더 짧고 읽기 좋다.
하지만 조건이 너무 많아지거나 로직이 복잡해지면 일반 for 문이 더 명확할 수 있다.
예를 들어 아래처럼 너무 복잡해지면:
result = [x * 2 for x in numbers if x % 2 == 0 if x > 10] |
오히려 일반 for 문으로 푸는 편이 읽기 쉬울 수 있다.
comprehension 의 시간복잡도
comprehension 도 결국 내부적으로는 순회이므로, 시간복잡도는 일반 for 문과 크게 다르지 않다.
[x for x in items]:O(n){x for x in items}: 평균적으로O(n){k: v for k, v in items}:O(n)[x for x in sorted(items)]:O(n log n)
즉 comprehension 이라고 해서 무조건 더 빠르다기보다, 같은 순회를 더 간결하게 표현한다고 이해하는 편이 정확하다.
자주 하는 실수
1. set 은 순서가 있다고 생각하는 경우
data = {"b", "a", "c"} |
이 코드는 정렬 순서를 보장하지 않는다.
순서가 필요하면 sorted(data) 를 사용해야 한다.
2. dict 반복 시 value 가 바로 나올 거라고 생각하는 경우
user = {"name": "Alice", "age": 20} |
여기서 item 은 value 가 아니라 key 다.
3. 인덱스가 필요한데 range(len(...)) 만 고집하는 경우
fruits = ["apple", "banana", "orange"] |
물론 동작은 하지만, 보통은 아래가 더 읽기 쉽다.
for i, fruit in enumerate(fruits): |
시간복잡도는 둘 다 보통 O(n) 이지만, enumerate() 쪽이 더 읽기 쉽고 Python 스타일에 가깝다.
4. comprehension 문법을 거꾸로 쓰는 경우
잘못된 예:
[for x in numbers] |
올바른 예:
[x for x in numbers] |
핵심은 항상 표현식이 먼저, for 가 나중 이라는 점이다.
자주 쓰는 패턴의 시간복잡도 요약
| 코드 패턴 | 시간복잡도 |
|---|---|
for x in my_list |
O(n) |
for k, v in my_dict.items() |
O(n) |
for x in my_set |
O(n) |
for i in range(n) |
O(n) |
이중 for 문 |
보통 O(n^2) |
x in my_list |
O(n) |
x in my_set |
평균 O(1) |
x in my_dict |
평균 O(1) |
for x in sorted(my_list) |
O(n log n) |
for x in sorted(set(data)) |
O(n log n) |
정리
Python의 for 문은 반복 가능한 객체를 순회하는 가장 기본적인 문법이다.
- 숫자 반복은
range() - 리스트와 튜플은 값을 하나씩 순회
set은 중복 제거에 유리하지만 순서를 보장하지 않음dictionary는 기본적으로 key 를 순회하고,items()가 가장 실무적- 인덱스가 필요하면
enumerate() - 여러 컬렉션을 함께 돌릴 때는
zip() - 시간복잡도는 반복 횟수와 반복 안의 연산을 같이 봐야 함
- membership check 는
list보다set/dict가 유리한 경우가 많음
특히 set 과 dict 는 Python에서 매우 자주 쓰이기 때문에, for 문과 함께 자연스럽게 사용할 수 있어야 한다.
처음에는 기본 문법부터 익히고, 그 다음에 items(), enumerate(), zip() 같이 자주 쓰는 패턴을 몸에 익히는 것이 좋다.