프로그램에서 이름, 음량, 알림 설정을 딕셔너리로 만들었는데 종료하면 값이 사라집니다. 텍스트 파일에 한 줄씩 적어도 되지만, 다시 읽을 때 어느 줄이 이름이고 어느 줄이 숫자인지 직접 구분해야 합니다. 이런 설정값은 JSON 파일로 저장하고 다시 파이썬 값으로 읽어 오면 다루기 편합니다.
앞의 파일 읽기와 쓰기 글은 문자열을 파일에 남기는 방법을 다뤘습니다. 여기서는 딕셔너리의 이름표와 숫자, 참/거짓 값을 함께 보관합니다. 이름표인 키와 그에 대응하는 값이 낯설다면 딕셔너리 기본 예제를 먼저 보면 됩니다.
확인 기준 : 2026년 9월 10일. Windows의 Python 3 환경에서 아래 예제를 각각 실행했습니다. Python 3 공식 문서의 JSON 변환 규칙도 확인했습니다. 터미널에서 python --version이 실행되는 상태를 전제로 하며, 추가 패키지는 설치하지 않습니다.

AI로 제작한 JSON 저장과 읽기 개념 일러스트입니다.
JSON은 파이썬 코드를 저장하는 형식이 아닙니다
JSON은 데이터의 구조와 값을 텍스트로 표현하는 규칙입니다. 이름표와 값을 묶을 때는 {}, 여러 값을 순서대로 담을 때는 []를 사용합니다. 파이썬 딕셔너리와 비슷해 보여도 별도의 형식이라서, 파이썬 코드를 그대로 적으면 읽지 못하는 경우가 있습니다.
파이썬에 기본으로 포함된 json 모듈은 이 두 표현 사이를 바꾸는 기능 모음입니다. 그 안의 dump()는 파이썬 데이터를 받아 JSON 형식으로 바꿔 열린 파일에 쓰는 함수이고, load()는 열린 파일의 JSON 내용을 읽어 파이썬 값으로 돌려주는 함수입니다. 데이터에 붙여 쓰는 메서드가 아니라 json.dump(...), json.load(...)처럼 모듈 이름 뒤에 붙여 호출합니다.
입력과 결과를 먼저 구분해 두세요. dump()에는 저장할 데이터와 쓰기용 파일을 차례로 넣습니다. 원본 딕셔너리는 바뀌지 않고 파일 내용이 바뀝니다. load()에는 읽기용 파일 하나를 넣습니다. 파일을 수정하지 않고 새 파이썬 값을 돌려주므로, 그 결과를 변수에 저장해서 사용합니다.
먼저 딕셔너리 하나를 settings.json에 저장합니다
빈 실습 폴더에 01_save.py를 만들고 아래 전체 코드를 저장합니다. 딕셔너리는 이름표와 값을 한 쌍씩 담는 자료형입니다. 여기서는 name, volume, notifications가 이름표입니다.
파일을 여는 open()과 사용이 끝나면 닫아 주는 with를 함께 씁니다. open() 괄호 안에는 파일 이름, 쓰기 모드 "w", 문자 저장 방식인 encoding="utf-8"을 넣습니다. as file은 열린 파일을 file이라는 이름으로 사용한다는 뜻입니다.
json.dump() 뒤쪽의 ensure_ascii=False는 한글을 읽기 쉬운 글자로 남기는 옵션이고, indent=2는 중첩 단계마다 두 칸씩 들여쓰는 옵션입니다. 둘 다 저장되는 데이터의 의미를 바꾸지는 않습니다. 실행 후에는 터미널의 완료 문구와 새 JSON 파일의 내용을 함께 확인합니다.
import json
settings = {
"name": "민지",
"volume": 30,
"notifications": True
}
with open("settings.json", "w", encoding="utf-8") as file:
json.dump(settings, file, ensure_ascii=False, indent=2)
print("저장 완료")
첫 줄의 import json은 파이썬에 들어 있는 JSON 기능을 불러옵니다. settings = {...}는 오른쪽 딕셔너리를 만들어 왼쪽 변수에 저장합니다. 문자열에는 따옴표를 붙이고, 숫자 30과 참을 뜻하는 True에는 따옴표를 붙이지 않습니다.
핵심 줄은 json.dump(저장할 값, 열린 파일, 옵션)으로 읽으면 됩니다. settings를 JSON 텍스트로 변환해 file에 씁니다. dump()의 반환값은 None이므로 settings = json.dump(...)처럼 대입하면 원래 변수를 잃습니다. 반환값 대신 저장된 파일을 확인하세요.
터미널을 실습 폴더에서 열고 실행합니다.
python 01_save.py
터미널 출력입니다.
저장 완료
생성된 settings.json을 편집기로 열면 다음 내용이 들어 있습니다.
{
"name": "민지",
"volume": 30,
"notifications": true
}
여기서 True가 소문자 true로 바뀐 것은 오류가 아닙니다. JSON의 참/거짓 표기 규칙에 맞춰 변환된 것입니다. 키와 문자열 값은 큰따옴표로 감싸고, 숫자에는 따옴표를 붙이지 않습니다.
주의하실 점은 "w"가 같은 이름의 기존 파일을 열면 내용을 비운다는 것입니다. 별도 실습 폴더에서 사용하세요. 저장 위치는 현재 작업 폴더이며 .py 파일의 폴더와 항상 같지는 않습니다. 파일이 보이지 않거나 읽을 때 경로 오류가 나면 FileNotFoundError와 상대경로 확인 방법을 참고하세요.
저장한 파일을 다른 프로그램에서 다시 읽습니다
이번에는 같은 폴더에 02_load.py를 만듭니다. 저장 코드와 읽기 코드를 나누면, 앞 프로그램이 끝난 뒤에도 값이 파일에 남아 있다는 것을 확인할 수 있습니다.
읽기 모드 "r"로 파일을 열고 json.load(file)에 넘깁니다. 오른쪽 json.load(file)이 먼저 실행된 뒤, 돌려준 값을 왼쪽 settings가 받습니다.
import json
with open("settings.json", "r", encoding="utf-8") as file:
settings = json.load(file)
print("이름 :", settings["name"])
print("음량 :", settings["volume"])
print("알림 :", settings["notifications"])
print("음량에 5 더하기 :", settings["volume"] + 5)
같은 실습 폴더의 터미널에서 실행합니다.
python 02_load.py
직접 실행한 결과입니다.
이름 : 민지
음량 : 30
알림 : True
음량에 5 더하기 : 35
settings["name"]은 name 키의 값을 꺼냅니다. 파일의 최상위 구조가 {...}여서 load()가 딕셔너리를 돌려주었습니다. 파일에 [...] 형태의 배열을 저장했다면 파이썬 리스트가 나옵니다. 따라서 JSON을 읽으면 언제나 딕셔너리가 된다고 생각하면 안 됩니다.
음량은 숫자로 복원되어 30 + 5를 계산할 수 있고, true는 파이썬의 True로 돌아왔습니다. 단, 파일에 "volume": "30"처럼 따옴표를 붙였다면 문자열이 됩니다. load()가 숫자처럼 보이는 문자열까지 자동으로 숫자로 바꾸지는 않습니다.
자주 쓰는 대응 관계는 다음과 같습니다. None은 값이 없음을 나타내는 파이썬 값이고, JSON에서는 null로 적습니다.
| 파이썬 값 | JSON 표현 | 다시 읽은 파이썬 값 |
|---|---|---|
| 딕셔너리 | 객체 {...} |
딕셔너리 |
| 리스트 | 배열 [...] |
리스트 |
| 문자열 | 큰따옴표로 감싼 문자열 | 문자열 |
| 정수, 실수 | 숫자 | 정수, 실수 |
True, False |
true, false |
True, False |
None |
null |
None |
이 표가 모든 파이썬 자료형을 그대로 보존한다는 뜻은 아닙니다. 숫자 키는 문자열 키로 바뀌고 튜플은 다시 읽으면 리스트가 됩니다. 집합 set이나 날짜 값은 기본 설정으로 저장하면 TypeError가 납니다. 처음에는 문자열 키를 가진 딕셔너리와 위 표의 값으로 구성하는 편이 예상한 구조를 유지하기 쉽습니다.
한글이 역슬래시 u로 보여도 반드시 깨진 것은 아닙니다
ensure_ascii의 기본값은 True입니다. 이 옵션을 빼면 민지가 JSON 파일에서 \ubbfc\uc9c0처럼 보일 수 있습니다. 문자를 다른 표기로 적은 것이며, json.load()로 읽으면 원래 한글로 복원됩니다. 테스트에서도 두 저장 방식이 같은 이름을 돌려주었습니다.
두 옵션은 역할이 다릅니다.
encoding="utf-8"은 파일을 어떤 문자 인코딩으로 읽고 쓸지 정합니다.ensure_ascii=False는 JSON 안에서 한글을\u...대신 한글 글자로 보이게 합니다.
파일을 사람이 직접 열어 수정할 계획이라면 두 옵션을 함께 쓰면 됩니다. 이미 다른 인코딩으로 저장되어 읽기부터 실패하는 파일은 ensure_ascii=False를 추가한다고 고쳐지지 않습니다. 그 옵션은 JSON을 쓸 때의 표기에 적용됩니다.
dump와 dumps는 마지막 s에서 입력과 출력이 달라집니다
파일 대신 변수에 JSON 텍스트만 만들 때는 dumps()를 씁니다. 파이썬 값을 받아 문자열을 돌려주며 파일은 만들지 않습니다. 반대로 loads()는 JSON 문자열을 받아 파이썬 값을 돌려줍니다. 여기서 문자열은 따옴표로 표현하는 텍스트 값입니다.
파일 저장과 혼동하기 쉬운 네 함수를 나란히 보면 이렇습니다.
| 함수 | 넣는 것 | 결과 |
|---|---|---|
json.dump(data, file) |
파이썬 값, 쓰기용 파일 | 파일에 쓰고 None 반환 |
json.load(file) |
읽기용 파일 | 파이썬 값 반환 |
json.dumps(data) |
파이썬 값 | JSON 문자열 반환 |
json.loads(text) |
JSON 문자열 | 파이썬 값 반환 |
아래 코드는 파일을 열지 않고 메모리 안에서만 변환합니다. 03_strings.py에 저장해 실행할 수 있습니다.
import json
text = json.dumps({"name": "민지"}, ensure_ascii=False)
print(text)
data = json.loads(text)
print(data["name"])
출력은 다음과 같습니다.
{"name": "민지"}
민지
첫 출력은 JSON 문자열이고, 두 번째는 복원한 딕셔너리에서 꺼낸 이름입니다. json.loads("settings.json")은 파일을 여는 코드가 아닙니다. settings.json이라는 글자 자체를 JSON 데이터로 해석하려 하므로 실패합니다. 파일 이름은 open()에 넣고, 열린 파일을 json.load()에 넘기세요.
JSONDecodeError가 나면 파일 내용의 문법을 봅니다
JSONDecodeError는 읽어 온 내용이 JSON 문법에 맞지 않을 때 발생하는 오류입니다. 파이썬 딕셔너리를 화면에 출력한 모양을 복사해 파일에 넣는 실수가 흔합니다. 아래는 의도적으로 실패하는 코드입니다.
import json
json.loads("{'volume': 30}")
오류의 마지막 줄입니다.
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
키를 작은따옴표로 쓴 것이 원인입니다. JSON 데이터는 {"volume": 30}처럼 큰따옴표로 적어야 합니다. 위 코드에서는 json.loads('{"volume": 30}')로 바꾸면 됩니다. 바깥 작은따옴표는 파이썬 문자열을 감싸는 표기이고, 그 안 큰따옴표가 실제 JSON 내용입니다.
파일을 직접 수정했다면 마지막 항목 뒤에 쉼표가 남지 않았는지, true를 파이썬 방식인 True로 쓰지 않았는지도 확인하세요. 빈 파일 역시 유효한 JSON이 아닙니다. 비어 있는 딕셔너리를 뜻하려면 내용이 {}여야 합니다.
오류에 나온 line과 column은 해석이 막힌 줄과 열입니다. 그 위치와 바로 앞의 쉼표, 따옴표를 비교하세요. 코드로 저장할 때는 str(딕셔너리)를 쓰기보다 json.dump()로 JSON 문법을 만들면 됩니다.
값을 바꿀 때는 이어쓰지 말고 읽고 수정한 뒤 저장합니다
일반 텍스트의 추가 모드 "a"를 JSON에도 적용하면 문제가 생깁니다. JSON 값 두 개를 그냥 이어 붙인 내용은 json.load()가 읽는 하나의 JSON 문서가 아닙니다. 같은 파일에 dump()를 연달아 두 번 호출해도 같습니다.
다음은 broken.json을 만들어 오류를 재현하는 전체 코드입니다. 이 파일도 같은 이름이 있으면 덮어씁니다.
import json
with open("broken.json", "w", encoding="utf-8") as file:
json.dump({"volume": 30}, file)
json.dump({"volume": 40}, file)
with open("broken.json", encoding="utf-8") as file:
json.load(file)
파일에는 {"volume": 30}{"volume": 40}이 들어가며, 직접 실행한 오류의 마지막 줄은 다음과 같습니다.
json.decoder.JSONDecodeError: Extra data: line 1 column 15 (char 14)
첫 번째 {...}를 다 읽었는데 두 번째 값이 더 남아 있어서 생긴 오류입니다. 음량을 바꾸려는 목적이라면 기존 파일을 먼저 읽고, 딕셔너리를 수정한 다음 전체를 한 번 저장하면 됩니다. 06_update.py로 저장해서 앞에서 만든 settings.json이 있는 폴더에서 실행하세요.
import json
with open("settings.json", "r", encoding="utf-8") as file:
settings = json.load(file)
settings["volume"] = 40
with open("settings.json", "w", encoding="utf-8") as file:
json.dump(settings, file, ensure_ascii=False, indent=2)
print("저장한 음량 :", settings["volume"])
출력은 저장한 음량 : 40입니다. 02_load.py를 다시 실행하면 음량은 40, 음량에 5를 더한 결과는 45가 됩니다. 이름과 알림 설정은 그대로 남습니다. 메모리의 settings["volume"]만 바꿨을 때는 파일이 바뀌지 않으며, 아래 dump()까지 실행해야 저장됩니다.
이 흐름은 작은 개인 실습용 설정 파일을 한 프로그램에서 다루는 예제입니다. 쓰는 도중 실패하면 파일이 불완전해질 수 있으므로 중요한 원본은 복사본으로 연습하세요. 여러 프로그램이 동시에 수정하는 데이터까지 이 코드가 보호하지는 않습니다.
여러 항목을 보관하려면 항목들을 리스트 하나에 담아 그 리스트를 한 번 저장하는 방식으로 확장할 수 있습니다. 지금은 settings.json의 음량을 바꾼 뒤 읽기 프로그램을 따로 실행해 보세요. 파일 내용이 바뀌었는지, 다시 읽은 값의 자료형까지 예상대로인지 확인하는 것이 다음 실습의 기준입니다.
참고한 공식 문서
'IT프로그래밍 > 파이썬' 카테고리의 다른 글
| 파이썬 FileNotFoundError 해결 : 파일이 있는데도 못 찾는 상대경로 문제 (0) | 2026.09.09 |
|---|---|
| 파이썬 import 사용법 : 직접 만든 모듈에서 함수 불러오기 (0) | 2026.09.07 |
| 파이썬 ModuleNotFoundError 해결 : pip와 실행 Python 경로 맞추기 (0) | 2026.09.04 |
| 파이썬 t-string 사용법 : f-string과 다른 점과 Python 3.14 처리 원리 (0) | 2026.09.02 |
| 파이썬 sorted와 sort 차이 : key와 lambda로 원하는 기준 정렬하기 (0) | 2026.09.01 |
| 파이썬 enumerate와 zip 사용법 : 번호와 두 리스트를 함께 꺼내기 (0) | 2026.08.26 |
| 파이썬 리스트 컴프리헨션 : for문 한 줄의 순서와 if 위치 (0) | 2026.08.21 |
| 파이썬 파일 읽기 쓰기 : with open으로 주문장을 남기는 방법 (0) | 2026.08.20 |
댓글