파이썬(Python) 딕셔너리 사용법, 자주 쓰는 동작을 직접 실행해 보니
파이썬 딕셔너리를 만들고 꺼내고 고치고 합치는 동작과 JSON 변환을 파이썬 3.15.0에서 한 번씩 실행한 기록입니다. 없는 키를 꺼낼 때 두 방식이 어떻게 다른지, Claude Code가 7.2초 걸려 짠 단어 세기 코드의 결과도 함께 실었습니다.
Finn ·

없는 키를 대괄호로 꺼내면 파이썬은 KeyError: 'email'을 내고 종료 코드 1로 멈춥니다. 그런데 같은 키를 get으로 꺼내면 None이 나오고 프로그램은 계속 돌아가죠. 이 글은 맥에서 Python 3.15.0으로 파이썬 딕셔너리의 자주 쓰는 동작을 한 번씩 실행하고, 코드와 출력을 그대로 옮긴 기록입니다. 마지막 단계에서는 Claude Code에게 단어 세기 코드를 맡겼고, 오류 없이(종료 코드 0) 끝났습니다.
결론: 없을 수 있는 키는 get, 반드시 있어야 하는 키는 대괄호
| 방법 | 이번 실행에서 나온 결과 | 언제 쓰나 |
|---|---|---|
user["name"] (대괄호 꺼내기) | 키가 있으면 값, 없으면 KeyError로 멈춤 | 반드시 있어야 하는 키라서 없으면 바로 멈춰야 할 때 |
user.get("email") | 없는 키는 None | 없을 수도 있는 키를 확인할 때 |
user.get("email", "없음") | 없는 키는 정한 기본값 | 없을 때 쓸 값이 정해져 있을 때(예: 개수 세기의 0) |
update | 없던 키는 추가, 있던 키는 덮어씀 | 여러 키를 한 번에 넣거나 바꿀 때 |
pop | 키를 지우고 그 값을 돌려줌 | 지운 값을 이어서 써야 할 때 |
del | 키를 지움 | 값 없이 지우기만 할 때 |
a | b (합치기) | 겹치는 키는 오른쪽 값이 남음 | 기본 설정 위에 사용자 설정을 얹을 때 |
json.dumps(..., ensure_ascii=False) | 한글이 그대로 든 str | 한글을 이스케이프 없이 JSON 문자열로 바꿀 때 |
AI 코딩 도구가 만든 코드를 읽고 고치려면 딕셔너리의 기본 동작부터 손에 익어야 합니다. 아래 순서대로 터미널에 붙여 넣으면 같은 흐름을 그대로 재현할 수 있어요.
- 파이썬 버전을 확인합니다.
- 딕셔너리를 만들고 대괄호와
get으로 값을 꺼냅니다. - 없는 키를 두 방식으로 꺼내 결과를 비교합니다.
- 값을 추가·수정하고
update,pop,del로 바꾸거나 지웁니다. items()로 키와 값을 함께 돌고,in으로 키가 있는지 검사합니다.|연산자로 두 딕셔너리를 합치고 컴프리헨션으로 새 딕셔너리를 만듭니다.json모듈로 JSON 문자열로 바꿨다가 되돌립니다.- Claude Code에게 단어 세기 코드를 맡기고 실행합니다.
함께 읽을 글
실행 환경과 버전 확인
모든 단계는 새 임시 폴더 하나에서, Homebrew로 설치된 python3로 실행했습니다. 코드는 단계마다 python3 - <<'PY' ... PY 형태로 표준 입력에 넣어 바로 돌렸죠. 먼저 버전부터 확인합니다.
$ python3 --version
Python 3.15.0딕셔너리는 어떻게 만들고 꺼낼까요?
Python 자습서의 자료 구조 장은 딕셔너리를 한 딕셔너리 안에서 키가 겹치지 않는 '키: 값' 쌍의 집합으로 생각하라고 설명합니다. 중괄호 안에 쉼표로 쌍을 나열하면 되고, 출력될 때도 같은 모양이에요.
$ python3 - <<'PY'
user = {"name": "Finn", "lang": "파이썬", "year": 2026}
print(user)
print(user["name"], user.get("lang"))
print(len(user), list(user.keys()))
PY
{'name': 'Finn', 'lang': '파이썬', 'year': 2026}
Finn 파이썬
3 ['name', 'lang', 'year']키가 있을 때는 대괄호와 get의 결과가 같습니다. len(user)는 쌍의 개수 3을, list(user.keys())는 넣은 순서대로 만든 키 목록을 보여줬어요.
파이썬 dict와 딕셔너리는 다른 건가요?
같은 것입니다. 딕셔너리의 자료형 이름이 dict이고, 자습서는 dict() 생성자로 키-값 쌍의 시퀀스나 키워드 인자에서 바로 딕셔너리를 만들 수도 있다고 안내합니다. 빈 딕셔너리는 {}로 만듭니다.
없는 키를 꺼내면 무슨 일이 생길까요?
그렇다면 키가 없을 때는 어떨까요? 이 단계만 종료 코드 1로 끝났습니다.
$ python3 - <<'PY'
user = {"name": "Finn"}
print(user.get("email"))
print(user.get("email", "없음"))
print(user["email"])
PY
None
없음
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
KeyError: 'email'자습서도 같은 내용을 말합니다. 대괄호로 없는 키를 꺼내면 KeyError가 나고, 이 오류를 피하려면 get을 쓰면 됩니다. get은 키가 없을 때 None을, 두 번째 인자를 주면 그 기본값을 돌려주죠.

그래서 사용자 입력이나 외부 API 응답처럼 키가 빠질 수 있는 데이터라면 get과 기본값을 쓰는 편이 안전합니다. 반대로 키가 반드시 있어야 하는 설정값이라면, 대괄호로 꺼내 빠졌을 때 바로 오류로 알아차리는 쪽이 낫다고 판단할 수도 있어요.
값을 추가·수정·삭제하는 방법
꺼내는 법을 익혔으니 이제 내용을 바꿔 볼 차례입니다.
$ python3 - <<'PY'
user = {"name": "Finn"}
user["lang"] = "파이썬"; print("추가:", user)
user["name"] = "핀"; print("수정:", user)
user.update({"year": 2026, "lang": "Python"}); print("update:", user)
removed = user.pop("year"); print("pop:", removed, user)
del user["lang"]; print("del:", user)
PY
추가: {'name': 'Finn', 'lang': '파이썬'}
수정: {'name': '핀', 'lang': '파이썬'}
update: {'name': '핀', 'lang': 'Python', 'year': 2026}
pop: 2026 {'name': '핀', 'lang': 'Python'}
del: {'name': '핀'}추가와 수정은 같은 문법입니다. 자습서 설명처럼 이미 쓰인 키에 값을 저장하면 예전 값은 잊히거든요. update는 없던 year를 넣으면서 있던 lang을 덮어썼고, pop은 지운 값 2026을 돌려줬습니다. del은 값을 돌려주지 않고 지우기만 해요.

키와 값을 함께 도는 방법
목록을 화면에 뿌리거나 점수를 비교할 때는 반복문이 필요하죠. 자습서는 items()를 쓰면 키와 값을 동시에 얻는다고 설명합니다.
$ python3 - <<'PY'
scores = {"국어": 90, "영어": 85, "수학": 95}
for subject, score in scores.items():
print(subject, score)
print("영어" in scores, "과학" in scores)
print(max(scores, key=scores.get))
PY
국어 90
영어 85
수학 95
True False
수학in은 키가 있는지 검사해 True, False로 답합니다. 마지막 줄처럼 max에 key=scores.get을 넘기면 값이 가장 큰 키인 수학이 나왔습니다.
두 딕셔너리를 합치는 방법
설정 기본값에 사용자 설정을 덮어씌우는 경우처럼, 두 딕셔너리를 합칠 일도 자주 생깁니다. 아래 실행에서 a | b로 합치면 두 쪽에 모두 있던 키는 오른쪽 b의 값이 남았습니다. 그래서 설정을 합칠 때는 기본 설정을 왼쪽, 사용자 설정을 오른쪽에 두고, 겹치는 키의 최종값이 의도한 쪽인지 한 번 출력해 확인하는 편이 좋습니다.
$ python3 - <<'PY'
a = {"x": 1, "y": 2}
b = {"y": 20, "z": 30}
print(a | b)
print({k: v * 10 for k, v in a.items()})
PY
{'x': 1, 'y': 20, 'z': 30}
{'x': 10, 'y': 20}이번 실행에서 두 쪽에 다 있던 키 y는 오른쪽 b의 값 20이 남았습니다. 둘째 줄은 딕셔너리 컴프리헨션으로, 자습서 표현대로 임의의 키와 값 표현식에서 새 딕셔너리를 만드는 문법이에요. 자습서는 {**odds, **evens}처럼 ** 언패킹으로 합치는 방법도 함께 보여 줍니다.

JSON 문자열로 바꾸는 방법
API 응답이나 설정 파일로 내보내려면 딕셔너리를 문자열로 바꿔야 합니다. 이때 쓰는 것이 json 모듈입니다.
$ python3 - <<'PY'
import json
user = {"name": "Finn", "tags": ["파이썬", "AI"]}
text = json.dumps(user, ensure_ascii=False)
print(text, type(text).__name__)
print(json.loads(text)["tags"])
PY
{"name": "Finn", "tags": ["파이썬", "AI"]} str
['파이썬', 'AI']dumps는 JSON 형식의 str을 만들고, loads는 다시 파이썬 객체로 되돌립니다. 그런데 왜 ensure_ascii=False를 넣었을까요? 설명서에 따르면 기본값 True에서는 ASCII가 아닌 문자가 이스케이프되고, False면 따옴표·역슬래시·제어 문자를 뺀 모든 문자가 그대로 나옵니다. 한글을 읽기 좋게 남기려면 이 옵션이 필요하죠.
한 가지 더 주의할 점이 있습니다. 설명서는 JSON의 키가 항상 문자열이라서, 숫자 키를 가진 딕셔너리를 JSON으로 바꿨다가 되돌리면 원래와 같지 않을 수 있다고 적고 있어요.
AI에게 단어 세기를 맡기면 어떤 코드가 나올까요?
마지막으로 로그인된 Claude Code 2.1.309에 --model opus로 단어 세기를 맡겼습니다. collections 모듈은 쓰지 말라는 조건을 붙였어요.
$ claude --model opus -p "문장 '사과 바나나 사과 포도 바나나 사과'에서 단어마다 몇 번 나왔는지 딕셔너리로 세어 출력하는 파이썬 코드만 출력해. collections 모듈은 쓰지 마. 설명이나 코드 블록 표시는 붙이지 마." > count.py && cat count.py && python3 count.py
counts = {}
for word in '사과 바나나 사과 포도 바나나 사과'.split():
counts[word] = counts.get(word, 0) + 1
print(counts)
{'사과': 3, '바나나': 2, '포도': 1}이 단계는 7.2초 걸렸고 종료 코드는 0이었습니다. 눈여겨볼 곳은 counts.get(word, 0) + 1입니다. 앞에서 본 '없는 키면 기본값' 동작을 써서, 처음 나온 단어도 오류 없이 0에서 세기 시작하죠.

다만 위 코드는 이번 한 번의 실행에서 나온 것입니다. 같은 지시를 다시 내리면 다른 코드가 나올 수 있어요. 그래서 AI가 쓴 딕셔너리 코드를 받았다면, 이 글처럼 바로 실행해 출력을 확인하고 없는 키를 대괄호로 꺼내는 줄이 있는지 살펴보는 편이 좋습니다.
측정 조건과 한계
- 컴퓨터: 맥 한 대(darwin arm64), Node.js v22.23.1
- 파이썬: Homebrew로 설치된
Python 3.15.0한 버전 - AI 도구: Claude Code 2.1.309, 모델
opus, 이미 로그인된 상태 - 실행 횟수: 단계마다 한 번씩
| 단계 | 걸린 시간 | 종료 코드 |
|---|---|---|
| 1 | 0.0초 | 0 |
| 3. 없는 키를 꺼내면 | 0.0초 | 1 |
| 8. Claude Code에게 단어 세기 맡기기 | 7.2초 | 0 |
파이썬 단계의 0.0초는 한 번 잰 값이라 속도 비교의 근거로 쓰기는 어렵습니다. Claude Code의 7.2초도 이 측정만으로는 무엇에 시간이 들었는지 가를 수 없어요. AI가 준 코드를 받았다면 user["…"]처럼 외부 데이터의 키를 대괄호로 꺼내는 줄부터 찾아, 그 키가 없을 수 있다면 get(키, 기본값)으로 바꿀지 판단하는 편이 좋습니다.
참고 자료
- 5. 자료 구조 docs.python.org
- json — JSON 인코더와 디코더 docs.python.org