Definition of JSON in Python
JSON, which stands for JavaScript Object Notation, is a lightweight and human-readable data exchange format. In Python, the built-in json module allows you to serialize (convert Python objects to JSON strings) and deserialize (convert JSON strings to Python objects) data with remarkable simplicity.
If you want to master Python as a whole, including JSON data manipulation, we recommend following our complete Python course which covers this topic in depth.
The JSON format has become an essential standard in modern web development. It is used for REST APIs, configuration files, data storage, and much more. Python, thanks to its native json module, offers seamless integration with this format.
JSON data types and their Python counterparts
Before diving into examples, it is essential to understand how JSON types are mapped to Python types and vice versa. This mapping is automatic when you use the json module.
| JSON Type | Python Type | JSON Example | Python Example |
|---|---|---|---|
| object | dict | {"name": "Alice"} | {'name': 'Alice'} |
| array | list | [1, 2, 3] | [1, 2, 3] |
| string | str | "hello" | 'hello' |
| number (int) | int | 42 | 42 |
| number (float) | float | 3.14 | 3.14 |
| true / false | bool | true | True |
| null | None | null | None |
The json module is part of Python's standard library. You don't need to install anything: a simple import json is all you need to start working with this format.
Main functions of the json module
The json module provides four main functions that you will use on a daily basis. They are divided into two pairs: one for working with strings, the other for working directly with files.
| Function | Direction | Source / Destination |
|---|---|---|
json.dumps() | Python → JSON | String |
json.loads() | JSON → Python | String |
json.dump() | Python → JSON | File |
json.load() | JSON → Python | File |
Mnemonic tip: the "s" at the end of dumps and loads stands for "string". These functions work with strings, while dump and load (without the "s") work with files.
Practical examples
Serializing a Python object to JSON (dumps)
The json.dumps() function converts a Python object into a JSON string. This is the most common operation when you need to send data to an API or store it as text.
import json
# Creating a Python dictionary
user = {
"name": "Alice Dupont",
"age": 30,
"email": "alice@example.com",
"languages": ["Python", "JavaScript", "Rust"],
"active": True,
"address": {
"city": "Paris",
"zip_code": "75001"
}
}
# Converting to a JSON string
json_string = json.dumps(user)
print(json_string)
# {"name": "Alice Dupont", "age": 30, "email": "alice@example.com", ...}
# With readable formatting (indentation)
json_formatted = json.dumps(user, indent=4, ensure_ascii=False)
print(json_formatted)The indent=4 parameter adds 4-space indentation to make the JSON readable. The ensure_ascii=False parameter preserves special characters like accents instead of encoding them as Unicode escape sequences.
Deserializing a JSON string to a Python object (loads)
The json.loads() function performs the reverse operation: it transforms a JSON string into a native Python object.
import json
# JSON string received (for example from an API)
json_data = '''
{
"product": "Laptop",
"price": 999.99,
"in_stock": true,
"features": ["16 GB RAM", "512 GB SSD", "15-inch screen"],
"promotion": null
}
'''
# Converting to a Python dictionary
product = json.loads(json_data)
print(type(product)) #
print(product["product"]) # Laptop
print(product["price"]) # 999.99
print(product["in_stock"]) # True (Python boolean)
print(product["promotion"]) # None (not "null")
# Accessing list elements
for feature in product["features"]:
print(f"- {feature}")Notice how true in JSON is automatically converted to True in Python, and null becomes None. This conversion is entirely transparent.
Reading and writing JSON files
In most real-world cases, you will work with JSON files rather than strings. The json.dump() and json.load() functions are designed for this purpose.
import json
# === WRITING to a JSON file ===
config = {
"application": "MyApp",
"version": "2.1.0",
"debug": False,
"database": {
"host": "localhost",
"port": 5432,
"name": "my_database"
},
"supported_languages": ["fr", "en", "es"]
}
with open("config.json", "w", encoding="utf-8") as file:
json.dump(config, file, indent=4, ensure_ascii=False)
print("config.json file created successfully!")
# === READING from a JSON file ===
with open("config.json", "r", encoding="utf-8") as file:
config_read = json.load(file)
print(config_read["application"]) # MyApp
print(config_read["database"]["port"]) # 5432Always use encoding="utf-8" when opening JSON files to avoid encoding issues, especially on Windows where the default encoding may differ.
Handling JSON parsing errors
When processing JSON data from external sources (APIs, user files, etc.), it is imperative to handle potential errors. The json module raises a json.JSONDecodeError exception if the JSON is malformed.
import json
# Invalid JSON (trailing comma)
invalid_json = '{"name": "Alice", "age": 30,}'
try:
data = json.loads(invalid_json)
except json.JSONDecodeError as e:
print(f"JSON parsing error: {e}")
print(f"Error position: line {e.lineno}, column {e.colno}")
# Handling a missing or corrupted JSON file
try:
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
except FileNotFoundError:
print("The file does not exist")
data = {} # Default value
except json.JSONDecodeError as e:
print(f"The file contains invalid JSON: {e}")
data = {}
Serializing custom objects
By default, the json module does not know how to serialize objects from your custom classes. You need to provide a custom encoder or a conversion function.
import json
from datetime import datetime, date
# Method 1: Using the 'default' parameter
def custom_converter(obj):
"""Converts non-serializable objects to JSON-compatible types."""
if isinstance(obj, (datetime, date)):
return obj.isoformat()
if isinstance(obj, set):
return list(obj)
raise TypeError(f"Object of type {type(obj)} is not serializable")
event = {
"title": "Python Conference",
"date": datetime(2025, 6, 15, 14, 30),
"tags": {"python", "development", "conference"}
}
json_result = json.dumps(
event,
default=custom_converter,
indent=2,
ensure_ascii=False
)
print(json_result)
# Method 2: Creating a custom JSONEncoder
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, set):
return sorted(list(obj))
return super().default(obj)
json_result2 = json.dumps(event, cls=MyEncoder, indent=2, ensure_ascii=False)
print(json_result2)Both methods are valid. The default parameter is simpler for one-off cases, while creating a custom JSONEncoder is preferable when you have reusable serialization logic throughout your project.
Advanced dumps parameters
The json.dumps() function offers many parameters to finely control the JSON output.
import json
data = {
"name": "Alice",
"scores": [95, 87, 92],
"address": {"city": "Lyon", "country": "France"}
}
# Sort keys alphabetically
print(json.dumps(data, sort_keys=True, indent=2))
# Customize separators for compact JSON
print(json.dumps(data, separators=(',', ':')))
# {"name":"Alice","scores":[95,87,92],"address":{"city":"Lyon","country":"France"}}
# Combining parameters for optimal output
optimized_json = json.dumps(
data,
indent=2,
ensure_ascii=False,
sort_keys=True,
separators=(',', ': ')
)
print(optimized_json)The separators parameter allows you to control spacing in the generated JSON. By using (',', ':') without spaces, you produce compact JSON ideal for network transfer, where every byte counts.
Using json with complex and nested data
In practice, you will often encounter complex JSON structures with multiple levels of nesting. Here is how to manipulate them efficiently.
import json
# Typical API response
api_response = '''
{
"status": "success",
"total": 2,
"users": [
{
"id": 1,
"name": "Alice Dupont",
"skills": ["Python", "Django"],
"projects": [
{"name": "REST API", "completed": true},
{"name": "Discord Bot", "completed": false}
]
},
{
"id": 2,
"name": "Bob Martin",
"skills": ["Python", "Flask"],
"projects": [
{"name": "Website", "completed": true}
]
}
]
}
'''
data = json.loads(api_response)
# Navigating through nested data
for user in data["users"]:
print(f"\n{user['name']}:")
print(f" Skills: {', '.join(user['skills'])}")
for project in user["projects"]:
status = "✅" if project["completed"] else "⏳"
print(f" {status} {project['name']}")
Best practices
To use the json module effectively in Python, here are the best practices we recommend:
- Always use
ensure_ascii=Falseif your data contains non-ASCII characters (accents, special characters). This produces more readable and often more compact JSON. - Systematically handle
json.JSONDecodeErrorexceptions when deserializing data from external sources. Never trust unvalidated JSON. - Use
indentfor debugging and storage, but remove it for network transfer. Compact JSON reduces bandwidth usage. - Prefer
encoding="utf-8"when opening any JSON file to ensure cross-platform compatibility. - Use
json.dumps()withsort_keys=Trueif you need deterministic results (useful for comparisons, hashing, or versioning). - Never store sensitive data (passwords, tokens) in plain text JSON files. Use environment variables or secret management solutions.
- Use dict to structure your data before serialization. The correspondence between Python dictionaries and JSON objects is direct and natural.
- Consider using dataclass to model structured data before converting it to JSON. They offer better readability and implicit type validation.
Python's json module does not natively handle comments in JSON files. If you need configuration files with comments, consider the TOML format (natively supported since Python 3.11) or YAML.
Frequently asked questions
What is the difference between json.dumps() and json.dump()?
json.dumps() (with an "s" for "string") converts a Python object into a JSON string that you can store in a variable or manipulate in memory. json.dump() (without the "s") writes JSON directly to an open file. The rule is simple: use dumps/loads for strings and dump/load for files.
Can you serialize tuples and sets to JSON?
tuple are automatically converted to JSON arrays during serialization, just like list. However, set are not directly serializable and will raise a TypeError. To serialize them, you need to convert them to lists, either manually or by using a custom encoder with the default parameter of json.dumps().
Is the json module suitable for very large files?
The standard json module loads the entire file into memory, which can be problematic for files of several gigabytes. For these use cases, consider libraries like ijson (incremental parsing), orjson, or ujson (faster alternatives). For most common uses (configuration files, API responses), the standard module is perfectly adequate and performant enough.
How can I learn to master JSON and Python in depth?
JSON manipulation is a fundamental skill for every Python developer, whether it's for consuming APIs, managing configurations, or exchanging data. To master this topic along with the entire Python ecosystem, we recommend following our dedicated Python course on Believemy. You will learn not only JSON manipulation but also all the skills needed to become an accomplished Python developer.