KR_JSON - somaz94/python-study GitHub Wiki
JSON(JavaScript Object Notation)์ ๋ฐ์ดํฐ๋ฅผ ๊ตํํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๊ฒฝ๋ ๋ฐ์ดํฐ ํ์์ด๋ค.
import json
# ๊ธฐ๋ณธ ๋ฐ์ดํฐ ํ์
๋ณํ
python_dict = {
"name": "John",
"age": 30,
"city": "Seoul"
}
# Python -> JSON
json_str = json.dumps(python_dict)
print(json_str) # {"name": "John", "age": 30, "city": "Seoul"}
# JSON -> Python
python_data = json.loads(json_str)
print(python_data["name"]) # John
# Python ํ์
๊ณผ JSON ํ์
๋งคํ
# dict -> object, list/tuple -> array, str -> string,
# int/float -> number, True/False -> true/false, None -> null
# ํ๊ธ ๋ฐ ์ ๋์ฝ๋ ์ฒ๋ฆฌ
korean_data = {"์ด๋ฆ": "ํ๊ธธ๋", "๋์": "์์ธ"}
json_str = json.dumps(korean_data, ensure_ascii=False)
print(json_str) # {"์ด๋ฆ": "ํ๊ธธ๋", "๋์": "์์ธ"}
โ
ํน์ง:
- ๊ฐ๋จํ ๋ฐ์ดํฐ ๋ณํ
- ๋ฌธ์์ด ์ง๋ ฌํ
- ๊ธฐ๋ณธ ๋ฐ์ดํฐ ํ์ ์ง์
- ์ธ์ด์ ๋ ๋ฆฝ์ ์ธ ๋ฐ์ดํฐ ํ์
- ์ฌ๋์ด ์ฝ๊ณ ์ฐ๊ธฐ ์ฌ์
- ๊ธฐ๊ณ๊ฐ ํ์ฑํ๊ณ ์์ฑํ๊ธฐ ์ฌ์
JSON ๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ ์ฅํ๊ณ ๋ถ๋ฌ์ค๋ ๋ฐฉ๋ฒ์ด๋ค.
# JSON ํ์ผ ์ฐ๊ธฐ
data = {
"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
}
with open('data.json', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4)
# JSON ํ์ผ ์ฝ๊ธฐ
with open('data.json', 'r', encoding='utf-8') as f:
loaded_data = json.load(f)
# ์ฌ๋ฌ ์ต์
ํ์ฉ
with open('formatted_data.json', 'w', encoding='utf-8') as f:
json.dump(data, f,
indent=2, # ๋ค์ฌ์ฐ๊ธฐ ๊ฐ๊ฒฉ ์ค์
sort_keys=True, # ํค๋ฅผ ์ํ๋ฒณ ์์ผ๋ก ์ ๋ ฌ
ensure_ascii=False, # ๋นASCII ๋ฌธ์ ๊ทธ๋๋ก ์ถ๋ ฅ
separators=(',', ': ')) # ๊ตฌ๋ถ์ ์ง์
# ๋์ฉ๋ ํ์ผ ์ฒ๋ฆฌ
def read_json_stream(file_path):
"""๋์ฉ๋ JSON ํ์ผ์ ํ ์ค์ฉ ์ฒ๋ฆฌ"""
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
if line.strip(): # ๋น ์ค ๊ฑด๋๋ฐ๊ธฐ
yield json.loads(line)
# JSONL(JSON Lines) ํ์ ์ฒ๋ฆฌ
def write_jsonl(data_list, file_path):
"""๊ฐ ํญ๋ชฉ์ JSON Lines ํ์์ผ๋ก ์ ์ฅ"""
with open(file_path, 'w', encoding='utf-8') as f:
for item in data_list:
f.write(json.dumps(item, ensure_ascii=False) + '\n')
โ
ํน์ง:
- ํ์ผ ์ ์ฅ/๋ก๋
- UTF-8 ์ธ์ฝ๋ฉ
- ๋ค์ฌ์ฐ๊ธฐ ์ง์
- ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- JSONL ํ์ ์ง์
- ํ์ ์ต์ ์ปค์คํฐ๋ง์ด์ง
๋ณต์กํ Python ๊ฐ์ฒด๋ฅผ JSON์ผ๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ด๋ค.
from datetime import datetime
from decimal import Decimal
import uuid
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Decimal):
return str(obj)
if isinstance(obj, uuid.UUID):
return str(obj)
# ์ฌ์ฉ์ ์ ์ ํด๋์ค ์ฒ๋ฆฌ
if hasattr(obj, 'to_json'):
return obj.to_json()
return super().default(obj)
# ์ฌ์ฉ์ ์ ์ ํด๋์ค
class User:
def __init__(self, name, created_at):
self.name = name
self.created_at = created_at
self.id = uuid.uuid4()
def to_json(self):
return {
'name': self.name,
'created_at': self.created_at,
'id': self.id
}
data = {
'user': User('John Doe', datetime.now()),
'balance': Decimal('10.52'),
'transaction_id': uuid.uuid4()
}
json_str = json.dumps(data, cls=CustomEncoder, indent=2)
print(json_str)
# ์ง๋ ฌํ/์ญ์ง๋ ฌํ ํจ์ ์ฌ์ฉ
def serialize(obj):
"""๊ฐ์ฒด๋ฅผ JSON ๋ฌธ์์ด๋ก ๋ณํ"""
return json.dumps(obj, cls=CustomEncoder)
def deserialize(json_str, custom_decoder=None):
"""JSON ๋ฌธ์์ด์ ๊ฐ์ฒด๋ก ๋ณํ"""
if custom_decoder:
return json.loads(json_str, object_hook=custom_decoder)
return json.loads(json_str)
# object_hook์ผ๋ก ์ปค์คํ
๊ฐ์ฒด ๋ณต์
def user_decoder(obj):
if 'name' in obj and 'created_at' in obj and 'id' in obj:
user = User(obj['name'], datetime.fromisoformat(obj['created_at']))
user.id = uuid.UUID(obj['id'])
return user
return obj
โ
ํน์ง:
- ์ปค์คํ ์ธ์ฝ๋
- ๋ณต์กํ ๊ฐ์ฒด ๋ณํ
- ์ ์ฐํ ํ์ฅ
- object_hook์ผ๋ก ์ญ์ง๋ ฌํ ์ปค์คํฐ๋ง์ด์ง
- ์ฌ์ฉ์ ์ ์ ํด๋์ค ์ง์
- ๊ธฐ๋ณธ ํ์ ์ผ๋ก ์๋ ๋ฐ์ดํฐ ํ์ ์ฒ๋ฆฌ
JSON ๋ฐ์ดํฐ๊ฐ ์ ์๋ ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ฅด๋์ง ๊ฒ์ฆํ๋ ๋ฐฉ๋ฒ์ด๋ค.
from jsonschema import validate, ValidationError, Draft7Validator
# ๊ธฐ๋ณธ ์คํค๋ง ์ ์
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0},
"email": {"type": "string", "format": "email"},
"tags": {
"type": "array",
"items": {"type": "string"},
"minItems": 1
},
"address": {
"type": "object",
"properties": {
"street": {"type": "string"},
"city": {"type": "string"},
"country": {"type": "string"}
},
"required": ["street", "city"]
}
},
"required": ["name", "age", "email"]
}
# ๊ฒ์ฆ ํจ์
def validate_json(data, schema):
try:
validate(instance=data, schema=schema)
return True, None
except ValidationError as e:
return False, str(e)
# ์ฌ์ฉ ์์
user_data = {
"name": "Alice Smith",
"age": 25,
"email": "[email protected]",
"tags": ["developer", "python"],
"address": {
"street": "123 Main St",
"city": "New York"
}
}
is_valid, error = validate_json(user_data, schema)
if is_valid:
print("๋ฐ์ดํฐ๊ฐ ์ ํจํฉ๋๋ค.")
else:
print(f"๊ฒ์ฆ ์คํจ: {error}")
# ๋ชจ๋ ์๋ฌ ํ๋ฒ์ ์์งํ๊ธฐ
def collect_all_errors(data, schema):
validator = Draft7Validator(schema)
errors = list(validator.iter_errors(data))
return [str(error) for error in errors]
# ์คํค๋ง ๋์ ์์ฑ
def generate_schema_from_data(data):
"""์ํ ๋ฐ์ดํฐ๋ก๋ถํฐ ๊ธฐ๋ณธ ์คํค๋ง ์์ฑ"""
schema = {"type": "object", "properties": {}}
for key, value in data.items():
if isinstance(value, str):
schema["properties"][key] = {"type": "string"}
elif isinstance(value, int):
schema["properties"][key] = {"type": "integer"}
elif isinstance(value, float):
schema["properties"][key] = {"type": "number"}
elif isinstance(value, bool):
schema["properties"][key] = {"type": "boolean"}
elif isinstance(value, list):
schema["properties"][key] = {"type": "array"}
elif isinstance(value, dict):
schema["properties"][key] = {"type": "object"}
elif value is None:
schema["properties"][key] = {"type": "null"}
return schema
โ
ํน์ง:
- ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ
- ์คํค๋ง ์ ์
- ์๋ฌ ์ฒ๋ฆฌ
- ๊ณ์ธต์ ๊ตฌ์กฐ ๊ฒ์ฆ
- ํ์ ๋ฐ ํ์ ๊ฒ์ฆ
- ์กฐ๊ฑด๋ถ ๊ฒ์ฆ ์ง์
- ๋์ ์คํค๋ง ์์ฑ
์ผ๋ฐ์ ์ธ JSON ์์
์ ์ํ ์ค์ฉ์ ์ธ ์์ ์ด๋ค.
# ์ค์ ๊ด๋ฆฌ ํด๋์ค
class Config:
def __init__(self, config_file):
self.config_file = config_file
self.config = self.load_config()
def load_config(self):
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
return self.create_default_config()
def save_config(self):
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(self.config, f, indent=4, ensure_ascii=False)
def create_default_config(self):
default_config = {
"app_name": "MyApp",
"version": "1.0.0",
"debug": True,
"logging": {
"level": "INFO",
"file": "app.log"
},
"database": {
"host": "localhost",
"port": 5432,
"name": "mydb"
}
}
return default_config
def get(self, key, default=None):
"""์ค์ ๊ฐ ๊ฐ์ ธ์ค๊ธฐ (์ ํ๊ธฐ๋ฒ ์ง์)"""
keys = key.split('.')
value = self.config
try:
for k in keys:
value = value[k]
return value
except (KeyError, TypeError):
return default
def set(self, key, value):
"""์ค์ ๊ฐ ์ค์ ํ๊ธฐ (์ ํ๊ธฐ๋ฒ ์ง์)"""
keys = key.split('.')
config = self.config
for k in keys[:-1]:
if k not in config or not isinstance(config[k], dict):
config[k] = {}
config = config[k]
config[keys[-1]] = value
self.save_config()
# RESTful API ์๋ต ์ฒ๋ฆฌ
def json_response(data, status=200):
"""JSON API ์๋ต ์์ฑ"""
from flask import Response # ํ์์ ๋ฐ๋ผ ์ค์น: pip install flask
return Response(
json.dumps(data, ensure_ascii=False),
status=status,
mimetype='application/json; charset=utf-8'
)
# JSON ๋ฐ์ดํฐ ๋ณํฉ
def merge_json(base, override):
"""๋ JSON ๊ฐ์ฒด ๋ณํฉ (์ค์ฒฉ ๊ตฌ์กฐ ์ง์)"""
if not isinstance(base, dict) or not isinstance(override, dict):
return override
result = base.copy()
for key, value in override.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = merge_json(result[key], value)
else:
result[key] = value
return result
# JSON ์ฐจ์ด ์ฐพ๊ธฐ
def find_json_diff(old, new):
"""๋ JSON ๊ฐ์ฒด ๊ฐ์ ์ฐจ์ด์ ์ฐพ๊ธฐ"""
diff = {}
# old์๋ ์์ง๋ง new์๋ ์๋ ํค
for key in old:
if key not in new:
diff[key] = {"old": old[key], "new": None}
# ํค๊ฐ ์์ชฝ ๋ชจ๋์ ์์ง๋ง ๊ฐ์ด ๋ค๋ฅธ ๊ฒฝ์ฐ
for key in new:
if key in old:
if isinstance(old[key], dict) and isinstance(new[key], dict):
nested_diff = find_json_diff(old[key], new[key])
if nested_diff:
diff[key] = nested_diff
elif old[key] != new[key]:
diff[key] = {"old": old[key], "new": new[key]}
else:
diff[key] = {"old": None, "new": new[key]}
return diff
โ
ํน์ง:
- ์ค์ ํ์ผ ๊ด๋ฆฌ
- ๊ธฐ๋ณธ๊ฐ ์ฒ๋ฆฌ
- ์๋ฌ ๋ณต๊ตฌ
- ๊ณ์ธต์ ์ค์ ์ ๊ทผ
- API ์๋ต ํฌ๋งทํ
- JSON ๊ฐ์ฒด ๋ณํฉ
- ๋ณ๊ฒฝ ์ฌํญ ์ถ์
- ์ ์ฐํ ๋ฐ์ดํฐ ๊ด๋ฆฌ
JSON์ ์น API์์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ๋ฐ์ดํฐ ๊ตํ ํ์์ด๋ค.
import requests
import json
# API ์์ฒญ ๋ฐ JSON ์ฒ๋ฆฌ
def fetch_data_from_api(url, params=None):
try:
response = requests.get(url, params=params)
response.raise_for_status() # 4xx, 5xx ์๋ฌ ํ์ธ
return response.json() # JSON ์๋ต์ ํ์ฑํ์ฌ Python ๊ฐ์ฒด๋ก ๋ณํ
except requests.exceptions.RequestException as e:
print(f"API ์์ฒญ ์๋ฌ: {e}")
return None
except json.JSONDecodeError as e:
print(f"JSON ํ์ฑ ์๋ฌ: {e}")
return None
# ๋ฐ์ดํฐ POST ์์ฒญ
def post_data_to_api(url, data):
headers = {'Content-Type': 'application/json'}
try:
response = requests.post(
url,
data=json.dumps(data, ensure_ascii=False),
headers=headers
)
response.raise_for_status()
return response.json()
except (requests.exceptions.RequestException, json.JSONDecodeError) as e:
print(f"API ์์ฒญ ์๋ฌ: {e}")
return None
# ๊ฐ๋จํ REST API ํด๋ผ์ด์ธํธ
class RestClient:
def __init__(self, base_url, token=None):
self.base_url = base_url
self.headers = {'Content-Type': 'application/json'}
if token:
self.headers['Authorization'] = f'Bearer {token}'
def get(self, endpoint, params=None):
url = f"{self.base_url}/{endpoint}"
response = requests.get(url, params=params, headers=self.headers)
response.raise_for_status()
return response.json()
def post(self, endpoint, data):
url = f"{self.base_url}/{endpoint}"
response = requests.post(
url,
data=json.dumps(data, ensure_ascii=False),
headers=self.headers
)
response.raise_for_status()
return response.json()
def put(self, endpoint, data):
url = f"{self.base_url}/{endpoint}"
response = requests.put(
url,
data=json.dumps(data, ensure_ascii=False),
headers=self.headers
)
response.raise_for_status()
return response.json()
def delete(self, endpoint):
url = f"{self.base_url}/{endpoint}"
response = requests.delete(url, headers=self.headers)
response.raise_for_status()
return response.status_code == 204 or response.json()
โ
ํน์ง:
- API ํต์ ์ JSON ํ์ฉ
- ์๋ต ๋ฐ์ดํฐ ํ์ฑ
- ์ค๋ฅ ์ฒ๋ฆฌ
- ์ธ์ฆ ํค๋ ๊ด๋ฆฌ
- RESTful API ํด๋ผ์ด์ธํธ
- CRUD ์์ ์ง์
- HTTP ๋ฉ์๋ ์ฒ๋ฆฌ
๋๋์ JSON ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ด๋ค.
import json
import time
import orjson # pip install orjson
import ujson # pip install ujson
# ์ฑ๋ฅ ๋น๊ต
def compare_json_libs(data, iterations=1000):
"""๋ค์ํ JSON ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฑ๋ฅ ๋น๊ต"""
results = {}
# ํ์ค json ๋ชจ๋
start = time.time()
for _ in range(iterations):
json_str = json.dumps(data)
json_obj = json.loads(json_str)
results['json'] = time.time() - start
# ujson ๋ชจ๋
try:
start = time.time()
for _ in range(iterations):
json_str = ujson.dumps(data)
json_obj = ujson.loads(json_str)
results['ujson'] = time.time() - start
except ImportError:
results['ujson'] = "๋ชจ๋ ์์"
# orjson ๋ชจ๋
try:
start = time.time()
for _ in range(iterations):
json_str = orjson.dumps(data)
json_obj = orjson.loads(json_str)
results['orjson'] = time.time() - start
except ImportError:
results['orjson'] = "๋ชจ๋ ์์"
return results
# ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌ๋ก ๋์ฉ๋ JSON ์ฒ๋ฆฌ
def process_large_json_stream(file_path, process_func):
"""๋์ฉ๋ JSON ํ์ผ์ ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ"""
import ijson # pip install ijson
with open(file_path, 'rb') as f:
# ํน์ ํจํด์ ๋ง๋ ๊ฐ์ฒด๋ง ์ถ์ถํ์ฌ ์ฒ๋ฆฌ
for item in ijson.items(f, 'items.item'):
process_func(item)
# ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ JSON ์์ฑ
def generate_large_json(file_path, n_items, chunk_size=1000):
"""๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ผ๋ก ๋์ฉ๋ JSON ํ์ผ ์์ฑ"""
with open(file_path, 'w', encoding='utf-8') as f:
f.write('{"items": [')
for i in range(n_items):
item = {
"id": i,
"name": f"Item {i}",
"value": i * 10
}
if i > 0:
f.write(',')
f.write(json.dumps(item))
# ๋ฉ๋ชจ๋ฆฌ ํ๋ณด๋ฅผ ์ํด ์ฃผ๊ธฐ์ ์ผ๋ก flush
if i % chunk_size == 0:
f.flush()
f.write(']}')
โ
ํน์ง:
- ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ
- ๋์ฒด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ฉ
- ์คํธ๋ฆฌ๋ฐ ํ์ฑ
- ์ฒญํฌ ๋จ์ ์ฒ๋ฆฌ
- ์ฑ๋ฅ ๋ฒค์น๋งํน
- ๋ฆฌ์์ค ์ต์ ํ
โ
๋ชจ๋ฒ ์ฌ๋ก:
- ์ธ์ฝ๋ฉ ์ง์ (UTF-8)
- ensure_ascii=False ํ์ฉํ์ฌ ํ๊ธ ๊ฐ๋ ์ฑ ํฅ์
- ์๋ฌ ์ฒ๋ฆฌ ๊ตฌํ (try-except)
- ์คํค๋ง ๊ฒ์ฆ์ผ๋ก ๋ฐ์ดํฐ ์ ํจ์ฑ ํ์ธ
- ํฐ ํ์ผ์ ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌ (ijson ํ์ฉ)
- ์ฑ๋ฅ ์ต์ ํ ํ์ ์ orjson, ujson ๊ณ ๋ ค
- ๋ณด์ ์ฃผ์ (๊ฒ์ฆ๋์ง ์์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ฃผ์)
- ๊น๋ํ ํฌ๋งทํ (indent ์ฌ์ฉ)
- ๋ฐ์ดํฐ ์์ถ ๊ณ ๋ ค (๋์ฉ๋ ๋ฐ์ดํฐ)
- ์ค์ฒฉ ๊ฐ์ฒด ์ฒ๋ฆฌ ์ ์ฌ๊ท ํจ์ ์ฌ์ฉ
- ์๊ฐ/๋ ์ง๋ ISO ํ์ ์ฌ์ฉ ๊ถ์ฅ
- ๋ณต์กํ ๊ฐ์ฒด๋ ์ง๋ ฌํ ๋ก์ง ๋ถ๋ฆฌ
- ์ค์ ํ์ผ ๋ฑ ์ค์ JSON์ ๋ฐฑ์ ์ ์ง
- ๋ด๋ถ ํฌ๋งท์ด ์๋ ๊ตํ ํฌ๋งท์ผ๋ก ํ์ฉ
- ์น API์์๋ Content-Type ํค๋ ํ์ธ
- ๋์๋ฌธ์ ๊ตฌ๋ถ์ ์ฃผ์ (JSON์ ๋์๋ฌธ์ ๊ตฌ๋ถ)