Python Essentials for AI Engineer

Course Content

Python Essentials for AI Engineer

6 sections · 48 lessons

How do you work with JSON files?


Turning an LLM reply into a dict you can trustRaw reply textStrip thejson code fencesjson.loads,catchJSONDecodeErrorCheck label andconfidence keysRetry once,quoting the errorStructured-output modes cut failures; this fallback catches the rest.
Parsing and validating are separate steps — valid JSON with the wrong keys is still a failed reply.

What you need to know

Load and dump

Python
import jsoncfg = {"model": "chat-small", "temperature": 0.2, "stop": None, "tags": ("faq", "hi")}with open("cfg.json", "w", encoding="utf-8") as f:    json.dump(cfg, f, indent=2, ensure_ascii=False)with open("cfg.json", encoding="utf-8") as f:    back = json.load(f)print(back)            # {'model': 'chat-small', 'temperature': 0.2, 'stop': None, 'tags': ['faq', 'hi']}print(json.dumps({1: "a"}))                              # {"1": "a"}  -> keys become stringsprint(json.dumps({"msg": "नमस्ते"}, ensure_ascii=False))   # {"msg": "नमस्ते"}
  • indent=2 makes files readable for humans; leave it out for compact payloads.
  • ensure_ascii=False keeps Hindi, Tamil or emoji readable instead of न... escapes.
  • The round trip is not perfect: the tuple came back as a list, and the int key 1 would come back as the string "1".

Types JSON cannot hold

Python
import jsonfrom datetime import datetimetry:    json.dumps({"at": datetime(2026, 9, 24, 10, 30)})except TypeError as e:    print(e)                     # Object of type datetime is not JSON serializableprint(json.dumps({"at": datetime(2026, 9, 24, 10, 30)}, default=str))# {"at": "2026-09-24 10:30:00"}

default= is a function called for any object JSON does not understand. Convert sets with list(), Decimal with str(), and NumPy arrays with .tolist().

JSON Lines

A normal JSON file holds one big value, so you must load all of it. JSON Lines (.jsonl) puts one JSON object on each line. You can stream it line by line, append new records without rewriting, and a single corrupt line does not ruin the file. Most fine-tuning and batch APIs use it.

A real-life example

You ask an LLM to return {"label": ..., "confidence": ...}. Most replies parse, but some arrive wrapped in Markdown code fences or with extra text, and json.loads raises json.JSONDecodeError. A small, defensive parser handles the common cases and reports the rest:

Python
import jsondef parse_reply(text):    text = text.strip()    if text.startswith("```"):        text = text.strip("`").removeprefix("json").strip()   # drop ```json ... ``` fences    try:        data = json.loads(text)    except json.JSONDecodeError as e:        return None, f"not JSON: {e.msg}"    if not {"label", "confidence"} <= data.keys():        return None, "missing keys"    return data, Noneprint(parse_reply('{"label": "refund", "confidence": 0.91}'))# ({'label': 'refund', 'confidence': 0.91}, None)print(parse_reply('```json\n{"label": "kyc", "confidence": 0.7}\n```'))# ({'label': 'kyc', 'confidence': 0.7}, None)print(parse_reply("Sure! The label is refund."))# (None, 'not JSON: Expecting value')

In production, a None result triggers one retry with the error message included in the prompt. Better still, use your provider's structured-output or JSON mode, or validate with Pydantic — but you still need this fallback for the replies that slip through.

Follow-up questions to expect

  • "What is the difference between load and loads?" — load reads from a file object; loads parses a string. The same goes for dump and dumps.
  • "How do you serialise a datetime?" — Convert it to an ISO string with .isoformat(), or pass default=str to json.dumps.
  • "Why use JSON Lines for datasets?" — Each line is independent, so you can stream, append and recover from a bad line without loading everything.