파이썬 JSON 설정 읽기: 중복 키와 NaN을 조용히 허용하지 않는 방법

JSON 설정의 중복 키는 object_pairs_hook으로, NaN·Infinity는 parse_constant로 거부하고 자료형 검증은 별도로 수행하세요.

확인일: 2026-10-24. Python 3.14 표준 라이브러리 예제입니다. Windows Python 3.14.4에서 합성 입력으로 로컬 실행과 assert 검사를 통과했습니다.

문법이 맞는데 설정값이 달라지는 이유는 무엇인가요?

같은 JSON 객체에 retry가 두 번 있으면 Python의 기본 디코더는 마지막 값을 남길 수 있습니다. 작성자가 의도하지 않은 값으로 설정이 바뀌어도 파싱 자체는 성공합니다. 이 글은 이미 읽은 사전에서 누락 키를 찾는 문제가 아니라, 사전으로 만들기 전에 중복 이름을 발견하는 문제를 다룹니다.

두 가지 훅은 각각 무엇을 검사하나요?

object_pairs_hook은 각 JSON 객체의 이름·값 쌍 목록을 받아 객체로 바꿉니다. unique_object에서 이미 본 이름이 나오면 고정 메시지의 ValueError를 냅니다. 중첩 객체에도 적용됩니다. parse_constant는 NaN, Infinity, -Infinity 같은 비표준 숫자 표기를 만났을 때 거부하도록 설정합니다. 따옴표로 감싼 "NaN"은 평범한 문자열이므로 이 예제에서는 허용합니다.

합성 입력으로 정상과 오류를 나눕니다

아래 read_config는 최상위 값이 객체인지도 확인합니다. 정상 설정과 중첩 true 값을 읽은 뒤, 같은 객체의 중복 이름·중첩 중복·비표준 숫자 상수·최상위 배열·마지막 쉼표를 검사합니다. 일반 문법 오류의 JSONDecodeError도 ValueError의 하위 클래스라 같은 테스트에서 잡힙니다. 실제 회사 설정이나 외부 API는 읽지 않습니다.

import json

def unique_object(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("중복 JSON 키")
        result[key] = value
    return result

def reject_constant(_text):
    raise ValueError("허용하지 않는 숫자 상수")

def read_config(text):
    value = json.loads(text, object_pairs_hook=unique_object,
                       parse_constant=reject_constant)
    if not isinstance(value, dict):
        raise ValueError("최상위 JSON 객체가 필요합니다")
    return value

assert read_config('{"retry": 3, "name": "NaN"}') == {"retry": 3, "name": "NaN"}
assert read_config('{"outer": {"enabled": true}}')["outer"]["enabled"] is True
for text in ['{"retry": 1, "retry": 9}', '{"outer": {"x": 1, "x": 2}}',
             '{"rate": NaN}', '{"rate": Infinity}', '{"rate": -Infinity}',
             '[]', '{"retry": 3,}']:
    try:
        read_config(text)
    except ValueError:
        pass
    else:
        raise AssertionError("잘못된 JSON이 통과했습니다")
print("정상 객체와 문자열 NaN 허용")
print("중첩 중복 키·비표준 숫자 상수·배열·문법 오류 거부 확인")

검증한 출력

정상 객체와 문자열 NaN 허용
중첩 중복 키·비표준 숫자 상수·배열·문법 오류 거부 확인

JSON strict=True만으로 충분하지 않나요?

디코더의 strict 옵션은 주로 문자열 안의 제어 문자 허용과 관련되며, 이 글의 중복 키·숫자 상수를 모두 금지하는 스위치가 아닙니다. 또한 allow_nan=False는 dumps 쪽 직렬화 옵션이므로 loads의 입력 거부와 혼동하지 마세요. 이 코드는 JSON을 출력하는 부분을 바꾸지 않습니다.

파싱 검증 뒤에도 남는 검사가 있나요?

이 로더는 retry가 정수인지, 음수가 아닌지, 허용된 키만 있는지까지 검사하지 않습니다. 그런 업무 스키마 검증은 반환 사전에서 이어서 해야 합니다. 일반 소수는 기본 float로 읽으므로 금액 정밀도와 매우 큰 지수 표기는 별도의 숫자 정책이 필요합니다. 길이·깊이가 과도한 비신뢰 JSON의 자원 고갈까지 막는 보안 샌드박스도 아닙니다. 입력 크기를 제한하고, 오류 처리 중 설정 원문이나 토큰을 로그에 남기지 마세요.

자주 묻는 질문

배열 안의 객체도 중복 키가 검사되나요?

객체 훅은 파싱되는 각 객체에 적용됩니다. 다만 이 read_config는 최상위 배열 자체를 허용하지 않는 추가 계약을 갖습니다.

이 로더가 모든 설정 오류를 잡나요?

아닙니다. 중복 이름·비표준 상수·최상위 객체 여부를 다룹니다. 필수 키, 자료형, 값 범위와 접근 권한은 별도 검증해야 합니다.

공식 출처와 관련 글

아래 공식 문서는 2026-10-24에 확인했습니다.

AI 보조로 작성했으며 위 로컬 예제만 검증했습니다. 외부 API·실제 업무 자료·GUI 실행이나 사람 전문가 검수를 주장하지 않습니다.

댓글

이 블로그의 인기 게시물

API 키 저장 방법: 해싱과 암호화의 차이, Fernet 예제

파이썬 Google Sheets API 연동: 서비스 계정 권한과 읽기·쓰기

Pandas 결측치 처리: isna, fillna, dropna 선택 기준