⚙️
중급 (Intermediate)
list/dict/set comp · yield · 메모리 효율
2주차 — 컴프리헨션과 제너레이터
리스트·딕셔너리·집합 컴프리헨션으로 한 줄에 변환·필터·매핑을 처리하고, yield로 만드는 제너레이터로 메모리 효율적인 코드를 짭니다.
comprehensiongeneratoryield
소요 시간
⏱ 2시간
난이도
📊 중급
선수 조건
🎯 1주차 (함수 심화)
결과물
한 줄 컴프리헨션 + 큰 데이터에 강한 제너레이터
이 강의에서 배우는 것
- 1리스트·딕셔너리·집합 컴프리헨션을 작성한다
- 2제너레이터 함수와 표현식을 이해한다
- 3메모리 효율적인 코드를 짠다
1. 리스트 컴프리헨션
[표현식 for 변수 in 시퀀스 if 조건] 한 줄로 리스트 생성.
python
# 기존
squares = []
for x in range(10):
squares.append(x * x)
# 컴프리헨션
squares = [x * x for x in range(10)]조건 추가:
python
even_sq = [x * x for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]중첩:
python
pairs = [(i, j) for i in range(3) for j in range(3) if i != j]2. 딕셔너리·집합 컴프리헨션
python
words = ["apple", "banana", "cherry"]
# 딕셔너리: {키: 값 for ...}
length_map = {w: len(w) for w in words}
# {'apple': 5, 'banana': 6, 'cherry': 6}
# 집합: {표현식 for ...}
unique_lens = {len(w) for w in words}
# {5, 6}3. 제너레이터 함수
return 대신 yield. 결과를 한 번에 만들지 않고, 필요할 때마다 하나씩.
python
def fib(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for x in fib(10):
print(x, end=" ") # 0 1 1 2 3 5 8 13 21 34리스트로 한 번에 보고 싶으면 list(fib(10)).
4. 제너레이터 표현식
대괄호 대신 소괄호 → 메모리 절약.
python
# 리스트 컴프리헨션 (메모리 다 잡아먹음)
total = sum([x * x for x in range(1_000_000)])
# 제너레이터 표현식 (한 번에 하나씩)
total = sum(x * x for x in range(1_000_000))5. 언제 어느 것?
| 상황 | 도구 |
|---|---|
| 작은 데이터 + 인덱스 필요 | 리스트 컴프리헨션 |
| 큰 데이터 + 한 번 순회 | 제너레이터 |
| 키-값 매핑 | 딕셔너리 컴프리헨션 |
| 중복 제거 | 집합 컴프리헨션 |
6. 자주 하는 실수
- 컴프리헨션이 너무 길고 복잡 — 가독성 떨어지면 그냥 for 루프
- 제너레이터를 두 번 순회 — 한 번 다 돌면 빈 상태. 다시 호출 필요.
- yield 가 함수 어디에든 있으면 함수 전체가 제너레이터 — return 으로 일반 값 못 돌려줌
7. FAQ
Q1. 컴프리헨션이 for문보다 항상 빠른가요?
보통 약간 빠름. 가장 큰 차이는 가독성과 의도 표현.
Q2. 제너레이터의 길이를 알 수 있나요?
안 됨. 길이가 필요하면 list로 변환 (메모리 사용).
Q3. yield 가 여러 개여도 되나요?
네. 호출할 때마다 다음 yield 까지 실행됨.
💻 예제 (examples)
실제로 실행해 결과를 확인할 수 있는 예제 코드입니다.
01_list_comp.py— 리스트 컴프리헨션
CODE
squares = [x * x for x in range(10)]
print(squares)
even_sq = [x * x for x in range(10) if x % 2 == 0]
print(even_sq)
# 중첩
pairs = [(i, j) for i in range(3) for j in range(3) if i != j]
print(pairs)
▶ 실행 결과
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 4, 16, 36, 64]
[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]02_dict_set_comp.py— 딕셔너리·집합 컴프리헨션
CODE
words = ["apple", "banana", "cherry"]
length_map = {w: len(w) for w in words}
print(length_map)
unique_lens = {len(w) for w in words}
print(unique_lens)
▶ 실행 결과
{'apple': 5, 'banana': 6, 'cherry': 6}
{5, 6}03_generator.py— 제너레이터 함수 (피보나치)
CODE
def fib(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
for x in fib(10):
print(x, end=" ")
print()
# 리스트로
print(list(fib(10)))
▶ 실행 결과
0 1 1 2 3 5 8 13 21 34
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]04_generator_expr.py— 제너레이터 표현식 (메모리 비교)
CODE
# 리스트는 메모리에 다 만들어둠
total1 = sum([x * x for x in range(1_000_000)])
# 제너레이터는 한 번에 하나씩
total2 = sum(x * x for x in range(1_000_000))
print(total1 == total2, total1)
▶ 실행 결과
True 333332833333500000📝 과제 (exercises)
직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.
과제 1
1~100 소수 (컴프리헨션)
목표: 컴프리헨션으로 1~100 사이 소수만 추출.
요구사항
- is_prime 함수 정의
- 리스트 컴프리헨션으로 필터링
입출력 예시
[2, 3, 5, 7, 11, 13, ..., 97]▶정답 코드 펼치기 / 접기
SOLUTION
def is_prime(n):
if n < 2: return False
return all(n % i for i in range(2, int(n**0.5) + 1))
primes = [n for n in range(1, 101) if is_prime(n)]
print(primes)
▶ 실행 결과
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]과제 2
단어 길이 매핑
목표: 단어 리스트 → {단어: 길이} 딕셔너리 (컴프리헨션).
요구사항
- dict comprehension 사용
입출력 예시
{'apple': 5, 'pear': 4, 'kiwi': 4, 'banana': 6}▶정답 코드 펼치기 / 접기
SOLUTION
words = ["apple", "pear", "kiwi", "banana"]
length_map = {w: len(w) for w in words}
print(length_map)
▶ 실행 결과
{'apple': 5, 'pear': 4, 'kiwi': 4, 'banana': 6}과제 3
큰 파일 라인 단위 제너레이터
목표: 파일을 라인 단위로 읽고 길이만 합계 (메모리 효율).
요구사항
- 파일을 한 줄씩 yield 하는 제너레이터 함수
- sum 으로 길이 합계
💡 힌트
with open(path) as f: for line in f: yield line
입출력 예시
라인 수: 3, 총 글자 수: 35▶정답 코드 펼치기 / 접기
SOLUTION
def lines(path):
with open(path, encoding="utf-8") as f:
for line in f:
yield line.rstrip("\n")
# 가상 파일 (실제로는 path 받음)
sample = ["첫 번째 줄입니다", "두 번째 줄", "세 번째 줄입니다 끝"]
# 데모 (제너레이터 흉내)
def lines_from_list(lst):
for x in lst:
yield x
count = 0
total = 0
for line in lines_from_list(sample):
count += 1
total += len(line)
print(f"라인 수: {count}, 총 글자 수: {total}")
▶ 실행 결과
라인 수: 3, 총 글자 수: 26