Skip to content
  • Serialization: JSON, CSV & pickle · Python

Serialization: JSON, CSV & pickle

LearnViaNotes @learnvianotes· 5 min read

Turning Python objects into bytes or text and back — JSON for APIs, CSV for tables, TOML/INI for config, pickle for Python-only caches, and struct for binary formats.

FormatModuleHuman-readableCross-languageSafe on untrusted input
JSONjsonYesYesYes
CSVcsvYesYesYes
TOMLtomllib (read-only)YesYesYes
INIconfigparserYesMostlyYes
picklepickleNoPython onlyNo — can run code
SQLitesqlite3No (queryable)YesYes
Packed binarystructNoYes (you define the layout)Yes

JSON basics & type mapping

Python
import json
user = {"name": "Asha", "skills": ["python", "sql"], "active": True, "manager": None}
text = json.dumps(user)                  # object → str
print(text)                              # {"name": "Asha", "skills": ["python", "sql"], "active": true, "manager": null}
print(json.loads(text)["skills"][0])     # python

print(json.loads(json.dumps({1: (1, 2)})))   # {'1': [1, 2]}   ← int keys become strings, tuples become lists
PythonJSONBack to Python
dictobject {}dict (keys always str)
list, tuplearray []list
strstringstr
int, floatnumberint / float
True / Falsetrue / falsebool
NonenullNone
set, datetime, Decimal, objectsTypeError— convert first

Formatting options

Python
import json
data = {"name": "Zoë", "tags": ["a", "b"], "id": 7}

print(json.dumps(data))                                         # {"name": "Zo\u00eb", "tags": ["a", "b"], "id": 7}
print(json.dumps(data, ensure_ascii=False, sort_keys=True))     # {"id": 7, "name": "Zoë", "tags": ["a", "b"]}
print(json.dumps(data, ensure_ascii=False, separators=(",", ":")))   # {"name":"Zoë","tags":["a","b"],"id":7}
Python
import json
print(json.dumps({"id": 7, "tags": ["a", "b"]}, indent=2))
Output
{
  "id": 7,
  "tags": [
    "a",
    "b"
  ]
}
OptionEffect
indent=2Pretty-print (config files, debugging)
sort_keys=TrueStable key order — diff-friendly output, cache keys
ensure_ascii=FalseKeep non-ASCII characters instead of \uXXXX escapes
separators=(',', ':')Most compact output (network payloads)
default=fnCalled for objects JSON can't encode
allow_nan=FalseReject NaN/Infinity, which are not valid JSON

Custom types: default and object_hook

Python
import json
from dataclasses import dataclass, asdict, is_dataclass
from datetime import date

@dataclass
class Event:
    title: str
    day: date
    tags: set

def encode(obj):
    if isinstance(obj, date):
        return obj.isoformat()
    if isinstance(obj, set):
        return sorted(obj)
    if is_dataclass(obj):
        return asdict(obj)
    raise TypeError(f"{type(obj).__name__} is not JSON serializable")

text = json.dumps(Event("launch", date(2026, 9, 29), {"b", "a"}), default=encode)
print(text)                                  # {"title": "launch", "day": "2026-09-29", "tags": ["a", "b"]}

def decode(d):                               # called for every JSON object, innermost first
    if "day" in d:
        d["day"] = date.fromisoformat(d["day"])
    return d

back = json.loads(text, object_hook=decode)
print(back["day"].year, type(back["day"]).__name__)   # 2026 date
Python
import json
try:
    json.loads("{'single': 'quotes'}")        # Python-style dict text is NOT JSON
except json.JSONDecodeError as e:
    print(e.msg, "at position", e.pos)        # Expecting property name enclosed in double quotes at position 1

CSV: reading & writing

Python
import csv, io

rows = [{"name": "Asha", "city": "Pune, MH"}, {"name": "Ravi", "city": 'Say "hi"'}]
buf = io.StringIO()
writer = csv.DictWriter(buf, fieldnames=["name", "city"])
writer.writeheader()
writer.writerows(rows)
print(buf.getvalue().splitlines())   # ['name,city', 'Asha,"Pune, MH"', 'Ravi,"Say ""hi"""']   ← commas and quotes are escaped for you

reader = csv.reader(io.StringIO(buf.getvalue()))
header = next(reader)
print(header, list(reader))       # ['name', 'city'] [['Asha', 'Pune, MH'], ['Ravi', 'Say "hi"']]

raw = "name,score\nasha,91\nravi,84\n"
scores = [int(r["score"]) for r in csv.DictReader(io.StringIO(raw))]
print(sum(scores) / len(scores))  # 87.5
Python
import csv, io
tsv = "a\tb\n1\t2\n"
print(list(csv.reader(io.StringIO(tsv), delimiter="\t")))    # [['a', 'b'], ['1', '2']]

buf = io.StringIO()
csv.writer(buf, quoting=csv.QUOTE_NONNUMERIC, lineterminator="\n").writerow(["x", 1.5, 2])
print(buf.getvalue().strip())                                # "x",1.5,2

pickle — Python objects as bytes

Python
import pickle

data = {"ids": (1, 2, 3), "tags": {"py"}, "nested": [b"raw", None, 3.5]}
blob = pickle.dumps(data)                    # tuples, sets, bytes: all preserved
restored = pickle.loads(blob)
print(type(blob).__name__, restored == data, type(restored["ids"]).__name__)   # bytes True tuple

sqlite3 — a database in the standard library

Python
import sqlite3

con = sqlite3.connect(":memory:")            # or a file path
con.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
with con:                                    # commits on success, rolls back on error
    con.executemany("INSERT INTO users (name) VALUES (?)", [("Asha",), ("Ravi",)])
print(con.execute("SELECT id, name FROM users ORDER BY id").fetchall())   # [(1, 'Asha'), (2, 'Ravi')]
print(con.execute("SELECT name FROM users WHERE id = ?", (2,)).fetchone())  # ('Ravi',)
con.close()

Config files: TOML & INI

Python
import tomllib, configparser

cfg = tomllib.loads("""
[server]
host = "0.0.0.0"
port = 8080
debug = false

[database]
pool = { min = 1, max = 5 }
""")
print(cfg["server"]["port"], cfg["server"]["debug"], cfg["database"]["pool"]["max"])   # 8080 False 5

cp = configparser.ConfigParser()
cp.read_string("""
[app]
name = notes
workers = 4
debug = yes
""")
print(cp["app"]["name"], cp.getint("app", "workers"), cp.getboolean("app", "debug"))   # notes 4 True

Binary layouts with struct

Python
import struct

# "<" little-endian, H = unsigned 16-bit, I = unsigned 32-bit, f = 32-bit float
packed = struct.pack("<HIf", 7, 65536, 1.5)
print(len(packed), packed.hex())             # 10 0700000001000000c03f
print(struct.unpack("<HIf", packed))         # (7, 65536, 1.5)
print(struct.calcsize("<HIf"), struct.calcsize("HIf"))   # 10 12   ← native mode adds alignment padding

JSON vs pickle — when would you use each?

How do you serialize a datetime or a custom object to JSON?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report