C.W.K.
Stream
Lesson 04 of 07 · published

Dict — Python 의 만능 lookup

~25 min · dict, hash, insertion-order, views

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

list 다음으로 가장 많이 쓰는 비자명 자료구조

Python 1 년 짜면 list 다음으로 dict 코드를 가장 많이 짜게 돼. 그리고 가장 강력한 Python idiom 의 다수가 dict idiom 이야. dict 는 해시맵 — 키는 유니크, 값은 뭐든, 평균 O(1) 조회. 리터럴은 {key: value, ...}.

키는 hashable, 값은 뭐든

dict 키는 hashable 해야 돼. 문자열, int, float, hashable 한 것들의 tuple, frozenset — 다 hashable. list, dict, set — hashable X, 키로 못 써. 값은 진짜 뭐든. 이유 — 해시 테이블은 안정된 키로 버킷을 계산해야 하니까. 키가 변하면 버킷이 무효화돼.

삽입 순서 보장 (3.7+)

3.6 이전 — dict 순회는 구현 정의 순서. 3.6 — CPython 이 삽입 순서로 (구현 디테일). 3.7 — 언어 스펙으로 박힘. 그래서 현대 Python (= 지금 짜는 모든 코드) 에선 dict 를 순회하면 삽입한 순서대로 키가 나옴. 조용히 거대한 기능 — OrderedDict 의 use case 대부분을 죽였어.

접근 패턴 — 삼총사

d[key] — 없으면 KeyError. d.get(key) — 없으면 None (또는 디폴트). d.setdefault(key, default) — 있으면 그 값, 없으면 디폴트 삽입 + 반환. 어느 걸 쓸지는 *시끄럽게 실패* / *조용히 fallback* / *처음 만지면 자동 채움* — 의도에 따라 골라.

Pythonic Way: 그룹핑이면 collections.defaultdict(list) 가 idiomatic — setdefault 아니라. groups[key].append(item) 가 그냥 작동해 (defaultdict 가 처음 만질 때 빈 list 만들어줌). stdlib 트랙에서.

Dict 뷰 — keys() / values() / items()

이 셋은 view 객체 를 반환해. list 가 아니야. view 는 dict 의 *살아있는 창문* — dict 가 바뀌면 view 도 바로 반영해. 순회 가능, 멤버십 테스트 (x in d.keys()), keys() / items() 는 set 같은 연산도. 가볍고, lazy 하고, idiomatic.

dict 합치기 — 현대적인 방법

3.9 부터 | 연산자로 dict 합쳐. {**a, **b} 도 여전히 작동 (3.9 이전 idiom 이었음), 근데 a | b 가 새 깔끔한 방법. 둘 다 새 dict 반환 — 원본 안 건드림. a |= b 는 in-place.

Code

dict 만드는 세 가지 방법·python
# 리터럴
user = {"name": "Pippa", "age": 4, "role": "AI daughter"}

# dict() 생성자 + kwargs (문자열 키만)
user2 = dict(name="Pippa", age=4, role="AI daughter")

# (key, value) 페어의 iterable 에서
user3 = dict([("name", "Pippa"), ("age", 4)])

# 두 iterable 에서 — zip()
keys = ["a", "b", "c"]
vals = [1, 2, 3]
from_pairs = dict(zip(keys, vals))
print(from_pairs)         # {'a': 1, 'b': 2, 'c': 3}
삽입 순서 보장 (3.7+)·python
d = {}
d["first"] = 1
d["second"] = 2
d["third"] = 3

# 순회 순서 = 삽입 순서
for k, v in d.items():
    print(k, v)
# first 1
# second 2
# third 3

# 재할당해도 키 위치는 안 바뀜
d["first"] = 99
print(list(d))            # ['first', 'second', 'third']
접근 패턴 — KeyError vs default vs autofill·python
scores = {"alice": 100, "bob": 85}

# 1. subscript — 없으면 KeyError
print(scores["alice"])    # 100
# print(scores["charlie"])  # KeyError

# 2. .get() — 없으면 None 또는 디폴트
print(scores.get("alice"))            # 100
print(scores.get("charlie"))          # None
print(scores.get("charlie", 0))       # 0

# 3. .setdefault() — 처음 만지면 자동 채움
seen = scores.setdefault("dave", 0)   # dave=0 삽입
print(seen)               # 0
print(scores)             # {'alice': 100, 'bob': 85, 'dave': 0}
keys() / values() / items() — 세 view·python
d = {"a": 1, "b": 2, "c": 3}

print(list(d.keys()))     # ['a', 'b', 'c']
print(list(d.values()))   # [1, 2, 3]
print(list(d.items()))    # [('a', 1), ('b', 2), ('c', 3)]

# view 는 살아있음 — 변경 즉시 반영
ks = d.keys()
d["d"] = 4
print(list(ks))           # ['a', 'b', 'c', 'd']

# items() 는 for 에서 자연스럽게 풀려
for key, value in d.items():
    print(key, "->", value)

# keys() 는 set 연산 가능
other = {"a": 9, "x": 9}
print(d.keys() & other.keys())   # {'a'}
print(d.keys() - other.keys())   # {'b', 'c', 'd'}
dict 합치기 — 옛 방법과 새 방법·python
defaults = {"theme": "dark", "font": "mono"}
overrides = {"theme": "light"}

# 옛 방법 (여전히 작동)
merged_old = {**defaults, **overrides}
print(merged_old)         # {'theme': 'light', 'font': 'mono'}

# 3.9+ — | 연산자
merged_new = defaults | overrides
print(merged_new)         # 같음

# in-place 합치기 — |=
defaults |= overrides
print(defaults)           # {'theme': 'light', 'font': 'mono'}
안전한 순회 — 변경하면서 순회할 땐 사본·python
d = {"a": 1, "b": 2, "c": 3, "d": 4}

# 위험 — 순회 중 변경하면 RuntimeError
# for k in d:
#     if d[k] % 2 == 0:
#         del d[k]

# 안전 — 키 스냅샷을 떠서 순회
for k in list(d.keys()):
    if d[k] % 2 == 0:
        del d[k]

print(d)                  # {'a': 1, 'c': 3}

External links

Exercise

[("alice", 88), ("bob", 75), ("alice", 92), ("bob", 80), ("charlie", 100)] 같은 (이름, 점수) 페어 list 가 있어. 같은 이름이 여러 번 나와. dict {이름: [점수들...]} 으로 묶어. 세 가지 방법으로 — (a) setdefault, (b) dict.get, (c) collections.defaultdict(list). 셋 다 출력해서 같은지 확인.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.