파이썬 교재 · 19편 / 27편

collections · itertools

표준 라이브러리 두 보석. 10줄짜리 작업이 1줄로 끝난다.

중급읽는 시간 6분2026-05-13
Counter, itertools.chain, groupby 를 활용한 코드 화면

5편의 list, 6편의 dict 가 입문자의 4대 자료구조였습니다. 그것들로도 거의 모든 일이 되지만, 같은 패턴이 반복되는 작업이 있어요 — "단어 빈도 세기", "키별로 그룹화", "두 리스트 이어 붙이기", "순열·조합 만들기". 직접 짜면 10-20줄, 표준 라이브러리의 collections·itertools 를 쓰면 1-3줄.

19편은 이 두 모듈의 단골 8가지를 정리합니다. 한 번 손에 익으면 자동화 코드 절대량이 30% 가까이 줄어요.

collections — 4가지 똑똑한 자료구조

Counter — 빈도 세기

from collections import Counter

# 문자 빈도
Counter("banana")
# Counter({'a': 3, 'n': 2, 'b': 1})

# 단어 빈도
text = "the quick brown fox jumps over the lazy dog the".split()
Counter(text).most_common(3)
# [('the', 3), ('quick', 1), ('brown', 1)]

# 두 Counter 의 차이·합
c1 = Counter("apple")
c2 = Counter("ape")
c1 - c2     # Counter({'p': 1, 'l': 1})
c1 + c2     # Counter({'a': 2, 'p': 3, 'l': 1, 'e': 2})

일반 dict 로 짜면 6줄이 한 줄. 로그 분석·텍스트 통계의 표준 도구입니다.

defaultdict — 빈 값 자동 초기화

from collections import defaultdict

# 보통 dict — KeyError 방지하려고 매번 조건문
groups = {}
for w in words:
    first = w[0]
    if first not in groups:
        groups[first] = []
    groups[first].append(w)

# defaultdict — 한 줄
groups = defaultdict(list)
for w in words:
    groups[w[0]].append(w)
# 없는 키 접근하면 빈 list 가 자동 생성

그룹화·카운팅·중첩 dict 만들기에서 빛납니다. 기본값 함수를 전달하면 그 함수의 결과로 자동 초기화. defaultdict(int) 면 카운터, defaultdict(list) 면 리스트 모음.

deque — 양쪽 끝에서 빠른 큐

from collections import deque

q = deque([1, 2, 3])
q.append(4)         # 뒤에 추가 — list 와 같음
q.appendleft(0)     # 앞에 추가 — list 는 O(n), deque 는 O(1)
q.popleft()         # 앞에서 꺼냄 — list 보다 훨씬 빠름
# deque([1, 2, 3, 4])

# 너비 우선 탐색(BFS)·캐시 라인·최근 N개 같은 곳에 표준
recent = deque(maxlen=5)    # 항상 마지막 5개만 유지
for n in range(10):
    recent.append(n)
list(recent)        # [5, 6, 7, 8, 9]

namedtuple — 가벼운 클래스 대안

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
p.x, p.y            # (3, 4)
p[0], p[1]          # (3, 4) — 튜플처럼도 됨

# 14편 dataclass 와 비슷한데 더 가볍고 불변

itertools — 반복의 시그니처

chain — 여러 리스트를 한 줄로

from itertools import chain

a = [1, 2, 3]
b = [4, 5]
c = [6, 7, 8]
list(chain(a, b, c))    # [1, 2, 3, 4, 5, 6, 7, 8]
# 또는 chain.from_iterable([a, b, c])

# 메모리 효율적 — 실제로 새 리스트를 만들지 않음
for x in chain(a, b, c):
    print(x)

groupby — 정렬된 데이터의 키별 그룹

from itertools import groupby

data = [
    ("A", 88), ("A", 92),
    ("B", 75), ("B", 80), ("B", 91),
    ("C", 60),
]

# 첫 요소(학점)로 그룹화 — 입력은 그 키로 미리 정렬되어 있어야
for k, group in groupby(data, key=lambda x: x[0]):
    scores = [s for _, s in group]
    print(f"{k}: 평균 {sum(scores)/len(scores):.1f}")
# A: 평균 90.0
# B: 평균 82.0
# C: 평균 60.0
⚠️ groupby 는 SQL 의 GROUP BY 와 다릅니다. 인접한 같은 키만 한 그룹으로. [A, B, A, B] 를 그대로 넣으면 4 그룹이 됩니다. 같은 키를 한 곳에 모으려면 sorted() 로 먼저 정렬.

combinations·permutations·product — 조합론

from itertools import combinations, permutations, product

list(combinations([1,2,3,4], 2))    # 순서 무관, 중복 없음
# [(1,2), (1,3), (1,4), (2,3), (2,4), (3,4)]

list(permutations([1,2,3], 2))      # 순서 있음
# [(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)]

list(product([1,2], ["a","b"]))     # 모든 조합 (곱집합)
# [(1,'a'), (1,'b'), (2,'a'), (2,'b')]

cycle·count·islice — 무한 반복의 안전한 제어

from itertools import cycle, count, islice

# 라운드 로빈
colors = cycle(["red", "green", "blue"])
[next(colors) for _ in range(7)]
# ['red', 'green', 'blue', 'red', 'green', 'blue', 'red']

# 무한 카운터에서 잘라내기
list(islice(count(1, 2), 5))   # 1부터 2씩, 5개
# [1, 3, 5, 7, 9]

📌 itertools 의 도구들은 거의 다 "이터레이터" 반환

실제 리스트가 아니라 "필요할 때 하나씩 꺼내는 발생기". 메모리 안전하지만 print(chain(a, b)) 하면 객체 주소만 보입니다. list(...) 로 펼치거나 for 로 순회.

마무리 — 알면 강력한 단축

이 8가지를 외울 필요는 없어요. "빈도 세야 한다 → Counter", "그룹화 → groupby (또는 defaultdict)", "여러 리스트 합치기 → chain" 같은 트리거만 머리에 있으면 됩니다. 실제 작업하다 "이거 직접 짜기 좀 길다" 싶으면 collections·itertools 를 한 번 떠올려보세요. 90% 답이 있어요.

다음 미션: ① 본인 일주일 매출 데이터에서 가장 많이 팔린 상품 Top 3 (Counter) ② 학생 리스트를 학점별로 그룹화 (defaultdict 또는 groupby) ③ 1~10 중 2개씩 조합 모두 출력 (combinations).

다음 편 미리보기

20편 — "파이썬 requests": 외부 패키지 1번 — HTTP 클라이언트. API 호출·웹 응답 받기.

📚 27편 파이썬 교재 시리즈 — 19/27편
← 18편 "타입 힌트" · 다음: 20편 "requests 사용법"

© 2026 주나이테크(주) @JUNAITECH