파이썬 JSON 파일이 한 줄로 저장될 때는 사람이 검토하는 파일인지 프로그램에 전달할 데이터인지 먼저 구분하고, 전자는 indent를 사용하고 후자는 기본 형식 또는 compact separators를 선택하면 됩니다. sort_keys=True는 내용을 바꾸기보다 키 순서를 정렬해 반복 실행 결과를 비교하기 쉽게 하는 옵션입니다. 이 글에서는 json.dump와 json.dumps의 차이까지 함께 살펴보며 저장 목적에 맞는 조합을 정리하겠습니다.
먼저 결론: 검토용과 전달용은 다르게 저장합니다
자동화 결과를 사람이 열어 확인하거나 Git diff로 비교한다면 들여쓰기가 있는 JSON이 편합니다. 다음처럼 indent=2를 지정하면 중첩 구조가 단계별로 보입니다.
import json
data = {
"name": "batch-job",
"enabled": True,
"steps": ["extract", "save"],
}
with open("config.json", "w", encoding="utf-8") as file:
json.dump(data, file, indent=2)
반대로 사람이 파일을 읽을 필요가 없고 다른 프로그램으로 넘길 문자열의 공백을 줄이고 싶다면 separators=(',', ':')를 고려할 수 있습니다. 다만 JSON의 유효성을 높여 주는 옵션은 아니므로, 단순히 한 줄이라는 이유만으로 무조건 compact 형식을 택할 필요는 없습니다.
indent가 JSON 줄바꿈을 결정하는 방식
Python 공식 문서의 json 인코더·디코더 문서에 따르면 indent=None은 줄바꿈을 넣지 않는 표현입니다. 그래서 별도 옵션 없이 json.dump(data, file)를 호출하면 작은 객체도 한 줄로 기록될 수 있습니다.
양의 정수 indent는 중첩 수준마다 그 수만큼 공백을 넣어 pretty-print합니다. 실무에서는 indent=2나 indent=4처럼 팀에서 읽기 편한 값을 정하면 됩니다. 여기서 중요한 것은 숫자 자체보다 같은 종류의 파일에 일관되게 적용하는 것입니다.
indent=0 또는 음수, 빈 문자열은 들여쓰기를 넣지 않으면서 줄바꿈만 삽입하는 동작입니다. 따라서 “한 줄이 아니게 만들되 공백 들여쓰기는 최소화하고 싶다”는 목적에는 이 선택도 맞을 수 있습니다. 하지만 사람이 중첩 구조를 빠르게 읽는 목적이라면 양의 정수 indent가 더 분명합니다.
sort_keys=True는 언제 함께 쓸까
sort_keys=True는 딕셔너리 키를 정렬합니다. 데이터의 의미나 키 이름을 바꾸는 옵션이 아니라 직렬화 결과의 순서를 일정하게 만드는 옵션입니다.
예를 들어 자동화가 매번 같은 설정을 저장하지만 입력을 조합하는 순서가 달라질 수 있다면 다음처럼 쓸 수 있습니다.
with open("config.json", "w", encoding="utf-8") as file:
json.dump(data, file, indent=2, sort_keys=True)
이렇게 하면 사람이 diff를 확인할 때 순서 변화와 실제 값 변화를 구분하기 쉬워집니다. Python 공식 문서도 sort_keys=True가 회귀 테스트에서 직렬화 결과를 비교할 때 유용하다고 설명합니다.
다만 기존 파일의 키 순서가 업무상 읽는 순서를 표현하고 있다면 정렬이 오히려 가독성을 해칠 수 있습니다. 사람이 보는 설정 파일이라도 자연스러운 순서를 유지하고 싶다면 sort_keys를 생략하고, 테스트나 재현 가능한 출력이 중요할 때만 추가하는 식으로 결정하면 됩니다.
separators=(‘,’, ‘:’)는 무엇을 줄이나
separators는 항목 사이와 키·값 사이에 사용할 구분자를 지정하는 튜플입니다. 공식 문서의 separators 설명에 나온 (',', ':')를 사용하면 구분자 주변의 공백을 제거해 compact한 JSON 표현을 만들 수 있습니다.
compact_text = json.dumps(data, separators=(",", ":"))
print(compact_text)
이 설정은 JSON 구조를 바꾸지 않고 표현에 들어가는 공백만 줄입니다. 따라서 전송 직전 문자열을 만들거나, 사람이 직접 읽고 수정하지 않는 중간 산출물을 작게 유지하려는 경우에 어울립니다. 반대로 운영자가 파일을 열어 값을 확인하고 수정해야 한다면 공백 절약보다 indent가 주는 가독성이 더 중요할 수 있습니다.
indent와 separators를 함께 지정할 때는 의도를 분명히 해야 합니다. pretty-print가 목적이면 indent 중심으로 작성하고, compact 표현이 목적이면 separators=(',', ':')를 사용합니다. 두 옵션을 섞어 결과를 추측하기보다 실제 출력 한 번을 확인해 팀의 포맷 규칙으로 고정하는 편이 안전합니다.
json.dump와 json.dumps의 차이
이름 끝의 s는 반환 대상이 문자열이라는 뜻으로 기억하면 편합니다. json.dump()는 JSON을 파일 객체처럼 write()를 지원하는 스트림에 직렬화하고, json.dumps()는 Python 객체를 JSON 형식의 문자열로 직렬화합니다. 두 함수는 indent, sort_keys, separators 같은 직렬화 옵션의 의미를 공유합니다.
파일에 바로 기록할 때는 dump를 사용합니다.
with open("result.json", "w", encoding="utf-8") as file:
json.dump(data, file, indent=2, sort_keys=True)
문자열을 변수로 받아 다른 함수에 넘기거나 요청 본문을 구성할 때는 dumps가 자연스럽습니다.
payload = json.dumps(data, separators=(",", ":"))
파일 객체에 dumps의 반환값을 쓰는 것도 가능하지만, 그 경우 문자열을 먼저 만들고 쓰는 단계가 나뉩니다. 반대로 dump의 반환값을 JSON 문자열처럼 사용하려고 하면 목적이 맞지 않습니다. “파일에 쓰는가, 문자열이 필요한가”를 먼저 정하면 함수 선택은 어렵지 않습니다.
목적별로 고르는 실무 기준
다음 순서로 결정하면 옵션을 필요 이상으로 넣지 않게 됩니다.
- 사람이 열어 검토하거나 변경 이력을 비교하는 파일인가요? 그렇다면
indent=2같은 양의 indent부터 적용합니다. - 반복 실행 결과의 키 순서까지 일정해야 하나요? 테스트나 diff가 목적일 때
sort_keys=True를 추가합니다. - 프로그램 전달용 문자열이며 공백을 줄이는 것이 의미가 있나요? 그때
json.dumps(..., separators=(",", ":"))를 선택합니다. - 파일 자체가 필요한가요, 문자열이 필요한가요? 파일이면
json.dump, 문자열이면json.dumps를 사용합니다.
예를 들어 사람이 검토할 자동화 결과라면 다음 조합이 무난합니다.
with open("result.json", "w", encoding="utf-8") as file:
json.dump(data, file, indent=2, sort_keys=True)
프로그램에 넘길 문자열이라면 다음처럼 목적을 드러낼 수 있습니다.
payload = json.dumps(data, separators=(",", ":"))
저장 전후에 확인할 것
포맷 옵션을 바꾼 뒤에는 눈으로 한 줄인지 확인하는 데서 끝내지 말고, 다시 읽을 수 있는 JSON인지도 확인해야 합니다. 포맷팅 옵션은 표현 방식을 바꾸지만 데이터 구조 자체를 검증해 주지는 않습니다.
또한 파일을 사람이 관리하는지, 자동화가 덮어쓰는 임시 결과인지에 따라 기준을 달리해야 합니다. 검토와 diff가 핵심이면 indent와 일관된 키 순서가 우선이고, 전달 문자열의 표현 크기를 줄이는 것이 핵심이면 compact separators가 후보입니다. 두 경우 모두 옵션을 많이 넣는 것이 좋은 것이 아니라, 다음 작업자가 무엇을 해야 하는지 분명한 형식이 좋은 형식입니다.
마무리
파이썬 JSON 파일이 한 줄로 저장되는 가장 흔한 이유는 indent=None인 기본 동작 때문입니다. 사람이 읽고 비교할 파일에는 indent를, 키 순서까지 안정적으로 맞출 필요가 있을 때는 sort_keys=True를, 프로그램 전달용 compact 문자열에는 separators=(',', ':')를 선택하면 됩니다. 마지막으로 파일을 만들 때는 json.dump, 문자열이 필요할 때는 json.dumps를 기준으로 구분하면 포맷 옵션을 목적에 맞게 관리할 수 있습니다.