Quick Flow
from itertools import chain, islice, product
flat = list(chain([1, 2], [3, 4]))
first_three = list(islice(range(10), 3))
pairs = list(product(["x", "y"], [1, 2]))itertools는 반복 흐름을 list로 바로 만들지 않고 조합할 때 유용합니다. chain·islice·product·groupby는 대부분 lazy iterator를 돌려주므로 소비 시점과 재사용 여부를 확인하고, groupby는 같은 key가 연속된 항목만 묶는다는 점을 구분합니다.
문법
기본형은 자주 쓰는 도구 import부터 보면 됩니다.
from itertools import chain, islice, product, groupby흐름 조합
여러 iterable을 한 흐름으로 붙이면 chain()
chain()은 여러 iterable을 하나의 긴 흐름처럼 이어 줍니다.
from itertools import chain
merged = chain([1, 2], [3, 4], [5])리스트를 계속 합치는 대신, 기존 iterable 성격을 유지하면서 연결하고 싶을 때 잘 맞습니다.
앞부분만 조금 보면 islice()
큰 iterator에서 일부만 미리 보고 싶거나, 처음 몇 개만 소비하고 싶다면 islice()가 자연스럽습니다.
from itertools import islice
preview = list(islice(range(100), 5))전체를 리스트로 바꾸지 않고 앞부분만 꺼낼 수 있다는 점이 핵심입니다.
가능한 조합을 만들면 product()
카테고리와 옵션, 좌표와 방향처럼 가능한 모든 조합을 만들고 싶을 때 product()를 씁니다.
from itertools import product
pairs = list(product(["A", "B"], [1, 2]))중첩 루프를 명시적으로 적는 대신 "조합 생성"이라는 의도를 직접 드러낼 수 있습니다.
그룹과 파이프라인
연속된 같은 키를 묶으면 groupby()
groupby()는 같은 키 전체를 알아서 모아 주는 도구가 아니라, 이미 정렬된 연속 구간을 묶는 도구입니다.
from itertools import groupby
rows = sorted(rows, key=lambda row: row["team"])
for team, group in groupby(rows, key=lambda row: row["team"]):
print(team, list(group))이 점 때문에 SQL의 GROUP BY처럼 생각하면 자주 헷갈립니다.
iterator 파이프라인이 읽기 어려워지면 리스트나 루프로 돌아간다
itertools는 강력하지만, 연산이 지나치게 길게 이어지면 오히려 흐름을 파악하기 어려울 수 있습니다.
이럴 때는 중간에 리스트로 끊거나, 명시적 루프로 다시 풀어 쓰는 편이 낫습니다.
주의할 점
groupby()는 같은 키 전체를 자동으로 모아 주지 않고, 연속된 구간만 묶습니다. 보통 먼저 정렬이 필요합니다.
# ❌ 정렬 없이 쓰면 같은 키가 여러 그룹으로 나뉠 수 있음
from itertools import groupby
rows = [{"team": "B"}, {"team": "A"}, {"team": "B"}]
for team, group in groupby(rows, key=lambda row: row["team"]):
print(team, list(group))
# ✅ 같은 키 기준으로 먼저 정렬
rows = sorted(rows, key=lambda row: row["team"])
for team, group in groupby(rows, key=lambda row: row["team"]):
print(team, list(group))참고 링크
2 sources