Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Read & Write JSON with json Module

Learn to read and write JSON data using Python's json module with a practical, step-by-step lesson. Covers core concepts, hands-on walkthrough, troubleshooting, and next steps.

Focus: read and write json data with json module

Sponsored

Every real-world Python application eventually needs to talk to another service, save configuration, or store structured data. That's where JSON comes in — and Python's built-in json module makes reading and writing JSON data as easy as opening a file. Without it, you'd be stuck manually parsing strings, handling nested structures, and fighting with data types. This lesson will turn you from a JSON novice into someone who can confidently serialize and deserialize Python objects in seconds.

The problem this lesson solves

Imagine you've built a weather script that collects data from an API. The API returns a string like '{"temp": 72, "city": "Berlin"}'. How do you turn that string into a Python dictionary you can use? Or suppose you need to save your app's state overnight — you want to write {'user': 'alice', 'score': 4500} to a file and load it back tomorrow. Writing your own parser is error-prone, slow, and fragile. The json module handles all of that: converting Python objects to JSON strings (serialization) and JSON strings back to Python objects (deserialization). It's built-in, battle-tested, and works with files, strings, and network streams.

Core concept / mental model

Think of the json module as a translator between Python land and JSON land.

  • Serialization (Python → JSON): You have a Python dict, list, string, number, boolean, or None. The json module turns it into a JSON-formatted string or writes it directly to a file.
  • Deserialization (JSON → Python): You have a JSON string or a file containing JSON. The json module parses it and returns the corresponding Python object.

The mapping is almost one-to-one:

Python JSON Example
dict object {'name': 'Bob'}{"name": "Bob"}
list / tuple array [1, 2, 3][1, 2, 3]
str string 'hello'"hello"
int / float number 4242
True / False boolean Truetrue
None null Nonenull

Pro tip: JSON object keys must be strings. Python dicts can have non-string keys, but json.dumps() will raise a TypeError unless you pass a custom encoder. Stick to string keys for smooth serialization.

The core functions you'll use every day are: - json.dumps() — serialize to a string - json.loads() — deserialize from a string - json.dump() — serialize and write to a file - json.load() — read from a file and deserialize

How it works step by step

Step 1: Import the module

import json — it's part of the standard library, no pip install needed.

Step 2: Serialize a Python object to a JSON string

import json

data = {
    "name": "Alice",
    "age": 30,
    "hobbies": ["reading", "hiking"],
    "is_active": True,
    "address": None
}

json_string = json.dumps(data, indent=2)
print(json_string)

Expected output:

{
  "name": "Alice",
  "age": 30,
  "hobbies": ["reading", "hiking"],
  "is_active": true,
  "address": null
}

Notice Python's True becomes JSON true, None becomes null. The indent=2 makes the output human-readable — omit it for minified output.

Step 3: Deserialize a JSON string back to Python

import json

json_string = '{"name": "Bob", "age": 25, "active": false}'
parsed = json.loads(json_string)
print(parsed)
print(type(parsed))
print(parsed["name"])

Expected output:

{'name': 'Bob', 'age': 25, 'active': False}
<class 'dict'>
Bob

Step 4: Write Python objects to a file

import json

config = {
    "host": "localhost",
    "port": 8080,
    "debug": True
}

with open("config.json", "w") as f:
    json.dump(config, f, indent=4)

Now check config.json — it contains:

{
    "host": "localhost",
    "port": 8080,
    "debug": true
}

Step 5: Read JSON from a file

import json

with open("config.json", "r") as f:
    loaded_config = json.load(f)

print(loaded_config["host"])  # localhost

Pro tip: Always use with open(...) to ensure the file is properly closed, even if an exception occurs.

Hands-on walkthrough

Let's build a mini contact book that saves and loads contacts from a JSON file.

import json

# Sample contacts data
contacts = [
    {"name": "Ana", "phone": "555-0100", "email": "ana@example.com"},
    {"name": "Ben", "phone": "555-0200", "email": "ben@example.com"}
]

# Save to file
with open("contacts.json", "w") as f:
    json.dump(contacts, f, indent=2)
print("Contacts saved to contacts.json")

# Load back
with open("contacts.json", "r") as f:
    loaded_contacts = json.load(f)

# Add a third contact
loaded_contacts.append({
    "name": "Carmen",
    "phone": "555-0300",
    "email": "carmen@example.com"
})

# Save updated list
with open("contacts.json", "w") as f:
    json.dump(loaded_contacts, f, indent=2)

print("Final contacts:")
for c in loaded_contacts:
    print(f"  {c['name']} — {c['email']}")

Expected output:

Contacts saved to contacts.json
Final contacts:
  Ana — ana@example.com
  Ben — ben@example.com
  Carmen — carmen@example.com

Now inspect contacts.json — it's a valid JSON array with three objects.

Compare options / when to choose what

Function Use Case Returns/Writes To Example
json.dumps() Convert Python object to JSON string (e.g., send via HTTP) String json.dumps({'a': 1})
json.loads() Parse JSON string from API or user input Python object json.loads('{"a": 1}')
json.dump() Write Python object directly to a file File object json.dump(data, f)
json.load() Read JSON from a file Python object json.load(f)

When should you use dumps+loads vs dump+load?

  • Use dumps/loads when you're working with strings: API responses, environment variables, or in-memory operations.
  • Use dump/load when you have a file path or file-like object: configuration files, data persistence, output logs.

Other serialization libraries: - pickle (Python-specific, can serialize custom objects but unsafe) - yaml (more human-readable config, needs pyyaml) - orjson (faster, but third-party)

Stick with json for interoperability and safety in most cases.

Troubleshooting & edge cases

1. TypeError: Object of type datetime is not JSON serializable

Problem: You're trying to serialize a datetime object, which Python doesn't know how to convert to JSON.

Solution: Convert to a string first, or pass a custom encoder.

import json
from datetime import datetime

now = datetime.now()
# This will fail:
# json.dumps(now)

# Solution: convert to string
json.dumps(str(now))  # '"2025-03-15 14:30:00.123456"'

2. json.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Problem: You're trying to parse an empty string, a file with no content, or malformed JSON.

Solution: Check the file contents first, validate with a try-except.

import json

data_string = ""  # empty

try:
    result = json.loads(data_string)
except json.JSONDecodeError as e:
    print(f"Invalid JSON: {e}")

3. Unicode characters turn into \uXXXX sequences

Problem: Japanese, emoji, or other Unicode characters are escaped.

Solution: Use ensure_ascii=False.

json.dumps({'emoji': '😊'}, ensure_ascii=False)
# '{"emoji": "😊"}'

4. Non-string dictionary keys

Problem: json.dumps({1: 'one'}) raises TypeError: keys must be str, int, float, bool or None.

Solution: Convert keys to strings explicitly.

import json
data = {1: 'one', 2: 'two'}
json.dumps({str(k): v for k, v in data.items()})
# '{"1": "one", "2": "two"}'

What you learned & what's next

You now know how to: - Explain what the json module does and why it's essential - Serialize Python objects to JSON strings and files using json.dumps() and json.dump() - Deserialize JSON strings and files back to Python objects using json.loads() and json.load() - Handle common edge cases like non-serializable types, empty data, and Unicode characters - Choose between dumps/dump and loads/load based on your use case

Next step: In the next lesson, you'll learn how to work with CSV files using Python's csv module — another ubiquitous data format for spreadsheets and data exports.

Practice recap

Open a Python REPL or create a script. Write a simple dictionary with your name, age, and a list of your favorite books. Use json.dumps() to serialize it, then json.loads() to deserialize it back. Save the dictionary to a file named favorites.json and read it back with json.load(). Now try adding a datetime object — see the error, then fix it by converting to a string.

Common mistakes

  • Forgetting to open the file in write ('w') or read ('r') mode — using 'w+' for reading will overwrite the file before you can load it.
  • Assuming json.load() returns a string — it returns a Python dict/list/etc., already parsed.
  • Trying to serialize custom objects (like datetime or class instances) without a default serializer — always convert to a primitive type first.
  • Ignoring json.JSONDecodeError — wrap json.loads() in a try-except when handling untrusted data.

Variations

  1. Use json.dumps(data, indent=2, sort_keys=True) to produce sorted, pretty-printed output for configuration files.
  2. For high-performance JSON processing, consider orjson or ujson — drop-in replacements that are faster, but the standard json module is fine for most apps.
  3. If you need to serialize complex Python objects (like custom classes), write a custom JSONEncoder subclass or use default=str in json.dumps().

Real-world use cases

  • Saving user preferences or game state to a local JSON file so data persists between app launches.
  • Parsing API responses from web services (most REST APIs return JSON) using json.loads(response.text).
  • Reading configuration files (e.g., config.json) for Python applications — json.load(open('config.json')).

Key takeaways

  • Python's json module has four main functions: dumps, loads, dump, load for serialization and deserialization.
  • JSON can only store dicts, lists, strings, numbers, booleans, and null — convert other types to these before serializing.
  • Use json.dump(obj, file) and json.load(file) when working with files, dumps/loads for in-memory strings.
  • Always handle json.JSONDecodeError when parsing untrusted JSON to avoid crashes.
  • Add indent=2 for human-readable output and ensure_ascii=False to preserve Unicode characters.
  • The json module is part of Python's standard library — no external dependencies required.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.