JSON(JavaScript Object Notation)은 경량 데이터 교환 형식으로, Python의 pickle과 비슷한 역할을 합니다. 다만 pickle 직렬화는 Python에 종속적인 반면, JSON은 대부분의 프로그래밍 언어에서 지원된다는 점이 큰 차이입니다. Python 표준 라이브러리의 json 모듈은 pickle 및 marshal 모듈과 유사한 객체 직렬화 기능을 제공합니다.
pickle 모듈과 마찬가지로 json 모듈도 Python 객체를 JSON 인코딩 문자열로 직렬화하는 dumps()와 loads() 함수를 제공하며, dump()와 load() 함수는 파일에 직렬화된 객체를 쓰거나 읽는 데 사용됩니다.
dumps()
이 함수는 Python 객체를 JSON 형식의 문자열로 변환합니다.
loads()
이 함수는 JSON 문자열을 다시 Python 객체로 변환(역직렬화)합니다.
다음 예제는 두 함수의 기본적인 사용법을 보여줍니다.
>>> import json
>>> data = ['Rakesh', {'marks': (50, 60, 70)}]
>>> s = json.dumps(data)
>>> s
'["Rakesh", {"marks": [50, 60, 70]}]'
>>> json.loads(s)
['Rakesh', {'marks': [50, 60, 70]}]
주요 옵션: sort_keys와 indent
dumps() 함수는 선택적 sort_keys 인자를 받습니다. 기본값은 False이며, True로 설정하면 딕셔너리의 키가 정렬된 순서로 JSON 문자열에 출력됩니다.
>>> data = {"marks": 50, "age": 20, "rank": 5}
>>> s = json.dumps(data, sort_keys=True)
>>> s
'{"age": 20, "marks": 50, "rank": 5}'
>>> json.loads(s)
{'age': 20, 'marks': 50, 'rank': 5}
또한 indent 매개변수에 숫자를 지정하면 pprint 출력과 유사하게 들여쓰기가 적용된 보기 좋은 형태의 JSON 문자열을 얻을 수 있습니다.
>>> data = ['Rakesh', {'marks': (50, 60, 70)}]
>>> s = json.dumps(data, indent=2)
>>> print(s)
[
"Rakesh",
{
"marks": [
50,
60,
70
]
}
]
객체 지향 API: JSONEncoder와 JSONDecoder
json 모듈에는 위 함수들에 대응하는 객체 지향 API도 포함되어 있으며, 모듈 안에 JSONEncoder와 JSONDecoder 두 클래스가 정의되어 있습니다.
JSONEncoder 클래스
이 클래스의 객체는 Python 데이터 구조를 JSON으로 인코딩합니다. 각 Python 데이터 타입은 아래 표와 같이 대응되는 JSON 타입으로 변환됩니다.
| Python | JSON |
|---|---|
| dict | object |
| list, tuple | array |
| str | string |
| int, float, int·float 기반 Enum | number |
| True | true |
| False | false |
| None | null |
JSONEncoder 클래스는 JSONEncoder() 생성자로 인스턴스화하며, 주요 메서드와 속성은 다음과 같습니다.
encode() − Python 객체를 JSON 형식으로 직렬화합니다.
iterencode() − 객체를 인코딩하고, 각 항목의 인코딩된 조각을 하나씩 생성(yield)하는 이터레이터를 반환합니다.
indent − 인코딩된 문자열의 들여쓰기 수준을 결정합니다.
sort_keys − true/false 값으로 키를 정렬된 순서로 출력할지 지정합니다.
check_circular − true이면 컨테이너 타입 객체의 순환 참조(circular reference) 여부를 검사합니다.
다음 예제는 Python 리스트 객체를 인코딩합니다.
>>> e = json.JSONEncoder()
>>> e.encode(data)
'["Rakesh", {"marks": [50, 60, 70]}]'
iterencode() 메서드를 사용하면 인코딩 결과가 조각 단위로 출력됩니다.
>>> for obj in e.iterencode(data):
... print(obj)
[
"Rakesh"
{
"marks"
:
[
50
, 60
, 70
]
}
]
JSONDecoder 클래스
이 클래스의 객체는 JSON 문자열을 다시 Python 데이터 구조로 디코딩하는 데 사용되며, 핵심 메서드는 decode()입니다. 다음 예제는 앞서 인코딩한 문자열에서 원래의 Python 리스트 객체를 복원합니다.
>>> d = json.JSONDecoder()
>>> d.decode(s)
['Rakesh', {'marks': [50, 60, 70]}]
파일·스트림과 함께 사용하기
json 모듈은 JSON 데이터를 파일류(file-like) 객체, 즉 디스크 파일이나 바이트 스트림에 쓰고 다시 읽어오기 위한 dump()와 load() 함수를 제공합니다.
dump()
이 함수는 Python 객체를 JSON 형식으로 인코딩해 파일에 기록합니다. 파일은 쓰기 권한으로 열려 있어야 합니다.
>>> data = ['Rakesh', {'marks': (50, 60, 70)}]
>>> fp = open('json.txt', 'w')
>>> json.dump(data, fp)
>>> fp.close()
이 코드는 현재 디렉터리에 'json.txt' 파일을 생성하며, 파일 내용은 다음과 같습니다.
["Rakesh", {"marks": [50, 60, 70]}]
load()
이 함수는 파일에서 JSON 데이터를 읽어 Python 객체를 구성합니다. 파일은 읽기 권한으로 열려 있어야 합니다.
>>> fp = open('json.txt', 'r')
>>> ret = json.load(fp)
>>> ret
['Rakesh', {'marks': [50, 60, 70]}]
>>> fp.close()
정리하면, 문자열 변환에는 dumps()/loads(), 파일 입출력에는 dump()/load()를 사용하고, 더 세밀한 제어가 필요할 때는 JSONEncoder와 JSONDecoder 클래스를 활용하면 됩니다.