파이썬의 리스트 컴프리헨션(List Comprehension)은 기존 리스트나 반복 가능한 객체(Iterable)를 바탕으로 새로운 리스트를 간결하게 생성하는 문법입니다.
자바의 Stream API에서 .map().filter().collect(Collectors.toList())를 한 줄로 줄여놓은 것과 매우 유사합니다.
1. 기본 문법
가장 기본적인 형태는 반복문만 사용하는 것입니다.
# [표현식 for 항목 in 반복가능객체]
squares = [x**2 for x in range(5)]
# 결과: [0, 1, 4, 9, 16]
- 표현식(Expression): 새로운 리스트에 담길 값 (위 예제에선
x**2)
- 항목(Item): 반복 객체에서 꺼내온 개별 요소 (
x)
- 반복가능객체(Iterable): 소스가 되는 객체 (
range(5))
2. 조건을 추가할 때 (Filtering)
if문을 사용하여 특정 조건에 맞는 데이터만 골라낼 수 있습니다. 자바 스트림의 .filter() 역할입니다.
# [표현식 for 항목 in 반복가능객체 if 조건문]
even_numbers = [x for x in range(10) if x % 2 == 0]
# 결과: [0, 2, 4, 6, 8]
- 작동 순서:
range에서 하나씩 꺼냄 -> if 조건 검사 -> 참이면 리스트에 추가.
3. 조건을 변경할 때 (If-Else / Mapping)
값에 따라 다른 결과를 넣고 싶을 때는 if-else 문을 표현식 자리(앞쪽)에 씁니다. 이는 파이썬의 삼항 연산자 문법을 활용하는 것입니다.
# [참일때값 if 조건문 else 거짓일때값 for 항목 in 반복가능객체]
result = ["Pass" if score >= 60 else "Fail" for score in [50, 80, 45, 90]]
# 결과: ['Fail', 'Pass', 'Fail', 'Pass']
- 주의: 필터링용
if는 맨 뒤에 오지만, 값을 선택하는 if-else는 반드시 맨 앞에 와야 합니다.
4. 중첩 반복문 (Nested For Loop)
리스트 안에 여러 개의 for문을 사용할 수 있습니다. 왼쪽에서 오른쪽 순서로 중첩됩니다.
# 2차원 리스트(행렬)를 1차원으로 풀기 (Flatten)
matrix = [[1, 2], [3, 4], [5, 6]]
flatten = [val for row in matrix for val in row]
# 결과: [1, 2, 3, 4, 5, 6]
# 위 코드는 아래의 일반 for문과 동일하게 작동합니다.
# for row in matrix:
# for val in row:
# flatten.append(val)
5. 중첩 리스트 생성 (Nested Comprehension)
리스트 안에 또 다른 리스트 컴프리헨션을 넣을 수 있습니다.
# 3x3 행렬 만들기
matrix = [[j for j in range(3)] for i in range(3)]
# 결과: [[0, 1, 2], [0, 1, 2], [0, 1, 2]]
6. 다른 데이터 타입도 가능합니다
문법 구조는 비슷하지만 괄호의 종류에 따라 결과 데이터 타입이 달라집니다.
- Set 컴프리헨션: 중복 제거가 필요할 때
{x % 3 for x in range(10)} # 결과: {0, 1, 2}
- Dict 컴프리헨션: 키-값 쌍을 만들 때
{x: x**2 for x in range(3)} # 결과: {0: 0, 1: 1, 2: 4}
- Generator 표현식: 메모리를 아끼기 위해 (소괄호 사용)
gen = (x**2 for x in range(1000000)) # 당장 리스트를 만들지 않고 대기함
💡 실무적인 조언
- 가독성 우선: 컴프리헨션이 너무 길어지거나 중첩이 3단계 이상 넘어가면 일반
for문으로 작성하는 것이 동료(혹은 미래의 나)를 위한 길입니다.
- 디버깅: 컴프리헨션 내부는 중단점(Breakpoint)을 찍기 어렵습니다. 로직이 복잡하면 별도의 함수로 빼서 호출하는 방식을 권장합니다.
- 성능: 일반
append 방식보다 리스트 컴프리헨션이 내부적으로 더 빠르게 최적화되어 작동합니다. 단순 생성/필터링 작업에는 적극적으로 사용하세요.
Java 개발자라면?
list.stream().filter(x -> x > 5).map(x -> x * 2).collect(Collectors.toList())
이 구문을 보실 때마다
[x * 2 for x in list if x > 5] 를 떠올리시면 됩니다!