Python for 문 사용법 정리 - list, set, dictionary 순회까지

Python for 문이란?

Python의 for 문은 반복 가능한 객체(iterable) 를 하나씩 순회할 때 사용한다.
C, Java처럼 “초기값; 조건; 증감” 형태를 직접 쓰는 방식이 아니라, 컬렉션이나 범위를 꺼내며 순회하는 방식에 더 가깝다.

가장 기본 형태는 다음과 같다.

for item in iterable:
print(item)

여기서 iterable 로 사용할 수 있는 대표 자료형은 다음과 같다.

  • list
  • tuple
  • string
  • set
  • dictionary
  • range()

가장 기본적인 for

fruits = ["apple", "banana", "orange"]

for fruit in fruits:
print(fruit)

실행 결과:

apple
banana
orange

이 코드는 fruits 안의 값을 하나씩 fruit 변수에 넣으면서 반복한다.


range() 와 함께 사용하기

숫자 범위를 반복하고 싶을 때는 range() 를 많이 사용한다.

1부터 4까지 반복

for i in range(1, 5):
print(i)

실행 결과:

1
2
3
4

range(start, stop) 에서 stop 값은 포함되지 않는다.

0부터 시작

for i in range(5):
print(i)

실행 결과:

0
1
2
3
4

증가폭 지정

for i in range(0, 10, 2):
print(i)

실행 결과:

0
2
4
6
8

문자열 순회

문자열도 iterable 이기 때문에 한 글자씩 순회할 수 있다.

text = "python"

for ch in text:
print(ch)

실행 결과:

p
y
t
h
o
n

list 와 함께 사용하는 방법

list 는 가장 흔하게 for 와 함께 사용하는 자료구조다.

numbers = [10, 20, 30, 40]

for number in numbers:
print(number)

합계 구하기

numbers = [10, 20, 30, 40]
total = 0

for number in numbers:
total += number

print(total)

실행 결과:

100

조건문과 함께 사용

numbers = [1, 2, 3, 4, 5, 6]

for number in numbers:
if number % 2 == 0:
print(number)

실행 결과:

2
4
6

tuple 과 함께 사용하는 방법

tuplelist 와 거의 같은 방식으로 순회할 수 있다.

colors = ("red", "green", "blue")

for color in colors:
print(color)

tuple 은 수정이 불가능하다는 점만 다르고, for 순회 방식은 거의 같다.


set 과 함께 사용하는 방법

set중복을 허용하지 않는 자료구조 다.
for 문으로 순회할 수 있지만, 중요한 특징이 하나 있다.

  • 순서가 보장되지 않는다
numbers = {1, 2, 3, 4, 5}

for number in numbers:
print(number)

출력 순서는 실행 환경에 따라 달라질 수 있다.

set 의 중복 제거 활용

data = [1, 1, 2, 2, 3, 4, 4, 5]

for value in set(data):
print(value)

이 방식은 중복 제거 후 순회할 때 간단하게 쓸 수 있다.

정렬해서 순회하고 싶다면

set 은 순서가 없으므로, 정렬된 순서가 필요하면 sorted() 와 같이 사용한다.

numbers = {5, 3, 1, 4, 2}

for number in sorted(numbers):
print(number)

실행 결과:

1
2
3
4
5

set중복 제거용, sorted(set_data)중복 제거 후 정렬 순회용 으로 이해하면 편하다.


dictionary 와 함께 사용하는 방법

dictionary 는 Python에서 매우 자주 쓰이는 자료구조다.
for 문과 함께 사용할 때는 무엇을 순회하는지 구분하는 것이 중요하다.

1. key 만 순회

기본적으로 for key in dict 형태는 key 를 순회한다.

user = {
"name": "Alice",
"age": 20,
"city": "Seoul"
}

for key in user:
print(key)

실행 결과:

name
age
city

2. value 꺼내기

user = {
"name": "Alice",
"age": 20,
"city": "Seoul"
}

for key in user:
print(user[key])

실행 결과:

Alice
20
Seoul

3. keys() 사용

for key in user.keys():
print(key)

for key in user: 와 거의 같은 의미다.

4. values() 사용

for value in user.values():
print(value)

실행 결과:

Alice
20
Seoul

5. items() 사용

가장 많이 쓰는 방식 중 하나다. key 와 value 를 같이 꺼낼 수 있다.

for key, value in user.items():
print(key, value)

실행 결과:

name Alice
age 20
city Seoul

실무에서는 dict 순회 시 items() 를 가장 많이 사용한다고 생각해도 크게 틀리지 않는다.


enumerate() 와 함께 사용하기

반복하면서 인덱스도 같이 필요할 때는 enumerate() 를 사용한다.

fruits = ["apple", "banana", "orange"]

for index, fruit in enumerate(fruits):
print(index, fruit)

실행 결과:

0 apple
1 banana
2 orange

1부터 시작하고 싶다면

for index, fruit in enumerate(fruits, start=1):
print(index, fruit)

실행 결과:

1 apple
2 banana
3 orange

range(len(list)) 보다 enumerate() 가 더 Python 답고 읽기 쉽다.


zip() 과 함께 사용하기

여러 개의 iterable 을 동시에 순회할 때는 zip() 을 사용한다.

names = ["Alice", "Bob", "Charlie"]
scores = [90, 85, 95]

for name, score in zip(names, scores):
print(name, score)

실행 결과:

Alice 90
Bob 85
Charlie 95

이 방식은 관련 있는 데이터를 같이 순회할 때 매우 편리하다.


for 문과 시간복잡도

Python에서 for 문을 사용할 때는 문법만 아는 것보다, 반복 횟수가 얼마나 되는지 같이 보는 것이 중요하다.

가장 기본적인 기준은 다음과 같다.

  • 원소를 n 개 가진 리스트를 한 번 순회하면 보통 O(n)
  • 이중 반복문으로 n x n 형태를 돌면 보통 O(n^2)
  • 반복문 안에서 어떤 연산을 하느냐에 따라 실제 비용이 더 커질 수 있음

for 문 자체보다, 몇 번 반복하는지 + 반복 안에서 무엇을 하는지 를 같이 봐야 한다.

가장 기본적인 O(n)

numbers = [1, 2, 3, 4, 5]

for number in numbers:
print(number)

리스트 길이가 n 이라면 이 코드는 원소를 한 번씩만 보기 때문에 보통 O(n) 이다.

중첩 반복문의 O(n^2)

numbers = [1, 2, 3, 4, 5]

for i in numbers:
for j in numbers:
print(i, j)

바깥쪽이 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]

if 5 in numbers:
print("found")

리스트는 처음부터 순차적으로 찾기 때문에 보통 O(n) 이다.

set 에서 in

numbers = {1, 2, 3, 4, 5}

if 5 in numbers:
print("found")

set 은 해시 기반이라 평균적으로 O(1) 에 가깝다.

dict 에서 in

user = {"name": "Alice", "age": 20}

if "name" in user:
print("found")

dict 도 해시 기반이라 key 조회는 평균적으로 O(1) 에 가깝다.

즉 단순 순회는 다들 O(n) 이지만:

  • membership check 는 list 보다 set / dict 가 훨씬 유리한 경우가 많다

for 문 안에서 list 검색을 하면 느려질 수 있다

초보자 코드에서 자주 나오는 패턴이다.

items = [1, 2, 3, 4, 5]
targets = [2, 4]

for item in items:
if item in targets:
print(item)

겉으로 보기엔 단순해 보이지만:

  • 바깥 반복: O(n)
  • item in targets: 리스트 탐색 O(m)

이므로 전체는 대략 O(n * m) 이 된다.

만약 targets 가 크다면 비효율적일 수 있다.

이럴 때는 set 으로 바꾸는 것이 좋다.

items = [1, 2, 3, 4, 5]
targets = {2, 4}

for item in items:
if item in targets:
print(item)

이 경우 평균적으로:

  • 바깥 반복: O(n)
  • item in targets: O(1)

이므로 전체는 대략 O(n) 에 가까워진다.

이게 set 을 자주 쓰는 대표 이유 중 하나다.


중첩 for

for 문 안에 또 다른 for 문을 넣을 수도 있다.

for i in range(2):
for j in range(3):
print(i, j)

실행 결과:

0 0
0 1
0 2
1 0
1 1
1 2

2차원 리스트를 순회할 때도 자주 사용한다.

matrix = [
[1, 2, 3],
[4, 5, 6]
]

for row in matrix:
for value in row:
print(value)

2차원 리스트에서 행이 r 개이고 열이 c 개라면, 이 코드는 보통 O(r * c) 로 볼 수 있다.


break, continue, else

break

반복을 즉시 종료한다.

for i in range(10):
if i == 5:
break
print(i)

continue

현재 반복만 건너뛰고 다음 반복으로 넘어간다.

for i in range(5):
if i == 2:
continue
print(i)

for ... else

Python의 for 문은 else 와 함께 사용할 수 있다.
반복이 break 없이 정상 종료되면 else 가 실행된다.

numbers = [1, 3, 5, 7]

for number in numbers:
if number == 2:
print("찾았다")
break
else:
print("없다")

실행 결과:

없다

list, set, dict 와 함께 쓰는 실전 예제

1. 리스트에서 짝수만 추출

numbers = [1, 2, 3, 4, 5, 6]
evens = []

for number in numbers:
if number % 2 == 0:
evens.append(number)

print(evens)

2. 중복 제거 후 출력

names = ["Tom", "Jane", "Tom", "Alice", "Jane"]

for name in set(names):
print(name)

이 코드는 보통 다음 비용으로 볼 수 있다.

  • set(names): O(n) 평균
  • for name in ...: O(n)

즉 전체적으로는 대략 O(n) 이다.

정렬까지 하고 싶다면:

for name in sorted(set(names)):
print(name)

이 경우는 정렬이 들어가므로:

  • set(names): O(n)
  • sorted(...): O(n log n)
  • 순회: O(n)

전체는 보통 O(n log n) 으로 본다.

3. 딕셔너리 값 합계 구하기

scores = {
"math": 90,
"english": 80,
"science": 95
}

total = 0

for score in scores.values():
total += score

print(total)

이 코드는 값을 한 번씩만 보기 때문에 O(n) 이다.

4. 딕셔너리에서 특정 조건 찾기

users = {
"user1": 18,
"user2": 25,
"user3": 30
}

for name, age in users.items():
if age >= 20:
print(name, age)

이것도 딕셔너리 항목을 한 번씩 보기 때문에 기본적으로 O(n) 이다.


컴프리헨션과 비교

for 문은 가장 기본적인 반복 방식이고, Python에서는 이를 더 짧게 쓰는 컴프리헨션 도 자주 사용한다.

예를 들어:

numbers = [1, 2, 3, 4, 5]
result = []

for number in numbers:
result.append(number * 2)

print(result)

위 코드는 리스트 컴프리헨션으로 더 짧게 쓸 수 있다.

numbers = [1, 2, 3, 4, 5]
result = [number * 2 for number in numbers]

print(result)

하지만 처음 학습할 때는 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]

result = [x * 2 for x in numbers]
print(result)

실행 결과:

[2, 4, 6, 8, 10]

조건도 붙일 수 있다.

evens = [x for x in numbers if x % 2 == 0]
print(evens)

실행 결과:

[2, 4]

2. Set Comprehension

중복 없는 set 을 한 줄로 만들 때 사용한다.

numbers = [1, 1, 2, 2, 3, 4]

result = {x for x in numbers}
print(result)

실행 결과:

{1, 2, 3, 4}

값을 변형할 수도 있다.

squares = {x * x for x in [1, 2, 3, 4]}
print(squares)

주의할 점은 set 이므로 순서를 보장하지 않는다는 점이다.

3. Dictionary Comprehension

dict 를 한 줄로 만들 때 사용한다.

numbers = [1, 2, 3, 4]

result = {x: x * x for x in numbers}
print(result)

실행 결과:

{1: 1, 2: 4, 3: 9, 4: 16}

기존 딕셔너리에서 조건에 맞는 항목만 다시 만들 수도 있다.

scores = {
"math": 90,
"english": 80,
"science": 95
}

high_scores = {k: v for k, v in scores.items() if v >= 90}
print(high_scores)

실행 결과:

{'math': 90, 'science': 95}

4. Generator Expression

리스트처럼 보이지만 [] 대신 () 를 사용하면 generator 가 된다.

numbers = (x * 2 for x in range(5))
print(numbers)

이건 바로 리스트가 만들어지는 것이 아니라, 필요할 때 값을 하나씩 꺼내는 generator 객체다.

for value in numbers:
print(value)

실행 결과:

0
2
4
6
8

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 = []

for x in range(5):
result.append(x * 2)

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"}

for value in data:
print(value)

이 코드는 정렬 순서를 보장하지 않는다.
순서가 필요하면 sorted(data) 를 사용해야 한다.

2. dict 반복 시 value 가 바로 나올 거라고 생각하는 경우

user = {"name": "Alice", "age": 20}

for item in user:
print(item)

여기서 item 은 value 가 아니라 key 다.

3. 인덱스가 필요한데 range(len(...)) 만 고집하는 경우

fruits = ["apple", "banana", "orange"]

for i in range(len(fruits)):
print(i, fruits[i])

물론 동작은 하지만, 보통은 아래가 더 읽기 쉽다.

for i, fruit in enumerate(fruits):
print(i, fruit)

시간복잡도는 둘 다 보통 O(n) 이지만, enumerate() 쪽이 더 읽기 쉽고 Python 스타일에 가깝다.

4. comprehension 문법을 거꾸로 쓰는 경우

잘못된 예:

[for x in numbers]
{for x in numbers}

올바른 예:

[x 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 가 유리한 경우가 많음

특히 setdict 는 Python에서 매우 자주 쓰이기 때문에, for 문과 함께 자연스럽게 사용할 수 있어야 한다.
처음에는 기본 문법부터 익히고, 그 다음에 items(), enumerate(), zip() 같이 자주 쓰는 패턴을 몸에 익히는 것이 좋다.

Share