Python으로 JSON 다루기 - glasslego/getting-started-with-python GitHub Wiki

1. JSON이란?

1.1 JSON 개념

**JSON (JavaScript Object Notation)**은 데이터를 저장하고 전송하기 위한 경량의 텍스트 기반 데이터 교환 형식

주요 특징

  • 경량성: XML보다 간결하고 읽기 쉬움
  • 언어 독립적: JavaScript에서 시작되었지만 대부분의 프로그래밍 언어에서 지원
  • 구조화: 키-값 쌍으로 구성된 구조화된 데이터
  • 표준화: RFC 7159 표준으로 정의됨

사용 용도

  • 웹 API: REST API의 데이터 전송 형식
  • 설정 파일: 애플리케이션 설정 저장
  • 데이터 저장: NoSQL 데이터베이스 (MongoDB 등)
  • 데이터 교환: 시스템 간 데이터 전송

1.2 JSON 문법 규칙

기본 문법

{
  "name": "Alice",
  "age": 25,
  "isStudent": false,
  "address": null,
  "hobbies": ["reading", "swimming", "coding"],
  "contact": {
    "email": "[email protected]",
    "phone": "010-1234-5678"
  }
}

데이터 타입

  1. 문자열: 쌍따옴표로 감싸기 "hello"
  2. 숫자: 정수나 소수 42, 3.14
  3. 불린: true 또는 false
  4. null: null
  5. 객체: 중괄호 {}로 감싸진 키-값 쌍
  6. 배열: 대괄호 []로 감싸진 값들의 목록

문법 규칙

  • 키는 반드시 문자열이고 쌍따옴표로 감싸야 함
  • 문자열은 쌍따옴표만 사용 (홑따옴표 불가)
  • 마지막 요소 뒤에 쉼표 금지
  • 주석 사용 불가

2. Python에서 JSON 다루기

2.1 json 모듈 기본 사용법

import json

# 1. Python 객체를 JSON 문자열로 변환 (직렬화/Serialization)
data = {
    "name": "Alice",
    "age": 25,
    "is_student": False,
    "grades": [85, 92, 78],
    "address": {
        "city": "Seoul",
        "zipcode": "12345"
    }
}

# dict를 JSON 문자열로 변환
json_string = json.dumps(data)
print("JSON 문자열:")
print(json_string)
print(f"타입: {type(json_string)}")

# 2. JSON 문자열을 Python 객체로 변환 (역직렬화/Deserialization)
json_text = '{"name": "Bob", "age": 30, "hobbies": ["music", "sports"]}'
python_obj = json.loads(json_text)
print("\nPython 객체:")
print(python_obj)
print(f"타입: {type(python_obj)}")
print(f"이름: {python_obj['name']}")

# 3. 들여쓰기로 보기 좋게 출력
pretty_json = json.dumps(data, indent=2)
print("\n들여쓰기 적용된 JSON:")
print(pretty_json)

# 4. 한글 문자 처리
korean_data = {
    "이름": "김철수",
    "나이": 30,
    "직업": "개발자",
    "취미": ["독서", "영화감상", "코딩"]
}

# ensure_ascii=False로 한글 문자 그대로 유지
korean_json = json.dumps(korean_data, ensure_ascii=False, indent=2)
print("\n한글 데이터 JSON:")
print(korean_json)

# 5. 키 정렬
sorted_json = json.dumps(data, indent=2, sort_keys=True)
print("\n키 정렬된 JSON:")
print(sorted_json)

2.2 JSON 파일 읽기와 쓰기

import json

# JSON 파일에 데이터 저장
students_data = {
    "course": "Python Programming",
    "semester": "2024-1",
    "instructor": "김선생",
    "students": [
        {
            "id": 1,
            "name": "Alice",
            "age": 22,
            "grades": {"midterm": 85, "final": 92},
            "active": True
        },
        {
            "id": 2,
            "name": "Bob",
            "age": 23,
            "grades": {"midterm": 78, "final": 88},
            "active": True
        },
        {
            "id": 3,
            "name": "Charlie",
            "age": 21,
            "grades": {"midterm": 92, "final": 95},
            "active": False
        }
    ]
}

# 파일에 JSON 데이터 쓰기
with open('students.json', 'w', encoding='utf-8') as f:
    json.dump(students_data, f, ensure_ascii=False, indent=2)
    
print("students.json 파일이 생성되었습니다.")

# 파일에서 JSON 데이터 읽기
with open('students.json', 'r', encoding='utf-8') as f:
    loaded_data = json.load(f)

print("\n파일에서 읽어온 데이터:")
print(f"과목: {loaded_data['course']}")
print(f"학기: {loaded_data['semester']}")
print(f"강사: {loaded_data['instructor']}")
print(f"학생 수: {len(loaded_data['students'])}")

# 학생 정보 출력
print("\n학생 목록:")
for student in loaded_data['students']:
    avg_grade = (student['grades']['midterm'] + student['grades']['final']) / 2
    status = "재학" if student['active'] else "휴학"
    print(f"  {student['name']} (ID: {student['id']}): 평균 {avg_grade:.1f}점 - {status}")

# 특정 학생 정보 수정
for student in loaded_data['students']:
    if student['name'] == 'Bob':
        student['grades']['final'] = 95  # Bob의 기말고사 점수 수정
        break

# 수정된 데이터를 다시 파일에 저장
with open('students_updated.json', 'w', encoding='utf-8') as f:
    json.dump(loaded_data, f, ensure_ascii=False, indent=2)

print("\n수정된 데이터가 'students_updated.json'에 저장되었습니다.")

# 실용적인 예시: 설정 파일 관리
config_data = {
    "database": {
        "host": "localhost",
        "port": 5432,
        "name": "myapp_db",
        "username": "admin"
    },
    "api": {
        "timeout": 30,
        "retries": 3,
        "base_url": "https://api.example.com"
    },
    "features": {
        "debug_mode": False,
        "logging_enabled": True,
        "cache_enabled": True
    }
}

# 설정 파일 저장
with open('config.json', 'w', encoding='utf-8') as f:
    json.dump(config_data, f, indent=2)

print("\n설정 파일 'config.json'이 생성되었습니다.")

# 설정 파일 읽기 및 사용
with open('config.json', 'r', encoding='utf-8') as f:
    config = json.load(f)

# 설정값 사용 예시
db_host = config['database']['host']
db_port = config['database']['port']
api_timeout = config['api']['timeout']
debug_mode = config['features']['debug_mode']

print(f"\n현재 설정:")
print(f"  데이터베이스: {db_host}:{db_port}")
print(f"  API 타임아웃: {api_timeout}초")
print(f"  디버그 모드: {'켜짐' if debug_mode else '꺼짐'}")

# JSON 파일에서 특정 데이터만 추출
def get_active_students(json_file):
    """재학 중인 학생들만 반환"""
    with open(json_file, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    active_students = []
    for student in data['students']:
        if student['active']:
            active_students.append({
                'name': student['name'],
                'id': student['id'],
                'average': (student['grades']['midterm'] + student['grades']['final']) / 2
            })
    
    return active_students

# 활성 학생 목록 조회
active_students = get_active_students('students.json')
print(f"\n재학 중인 학생 ({len(active_students)}명):")
for student in active_students:
    print(f"  {student['name']} (ID: {student['id']}): 평균 {student['average']:.1f}점")

# 여러 JSON 파일 처리
json_files = ['students.json', 'config.json']

for filename in json_files:
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            data = json.load(f)
        print(f"\n'{filename}' 파일 정보:")
        print(f"  키 개수: {len(data)}")
        print(f"  최상위 키들: {list(data.keys())}")
    except FileNotFoundError:
        print(f"'{filename}' 파일을 찾을 수 없습니다.")
    except json.JSONDecodeError as e:
        print(f"'{filename}' 파일의 JSON 형식이 올바르지 않습니다: {e}")

# 안전한 JSON 파일 처리 함수
def safe_load_json(filename, default=None):
    """안전하게 JSON 파일을 로드하는 함수"""
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return json.load(f)
    except FileNotFoundError:
        print(f"파일 '{filename}'을 찾을 수 없습니다.")
        return default
    except json.JSONDecodeError as e:
        print(f"JSON 파싱 오류: {e}")
        return default
    except Exception as e:
        print(f"예상치 못한 오류: {e}")
        return default

# 안전한 파일 로드 테스트
safe_data = safe_load_json('nonexistent.json', {})
print(f"\n존재하지 않는 파일 로드 결과: {safe_data}")

safe_students = safe_load_json('students.json', [])
print(f"안전하게 로드된 학생 수: {len(safe_students.get('students', []))}")

마무리

JSON은 현대 웹 개발과 데이터 교환에서 필수적인 형식입니다. Python의 json 모듈을 사용하면:

핵심 기능

  • json.dumps(): Python 객체 → JSON 문자열
  • json.loads(): JSON 문자열 → Python 객체
  • json.dump(): Python 객체 → JSON 파일
  • json.load(): JSON 파일 → Python 객체

중요 옵션

  • indent=2: 들여쓰기로 가독성 향상
  • ensure_ascii=False: 한글 등 non-ASCII 문자 그대로 유지
  • sort_keys=True: 키를 알파벳 순으로 정렬