How to Parse JSON in Python: Complete Guide
JSON (JavaScript Object Notation) is the most common data format for APIs, configuration files, and data exchange between systems. Python's built-in json module makes parsing JSON straightforward, but there are several methods and edge cases worth understanding. This guide covers everything you need to know.
Parsing a JSON String with json.loads()
The most common operation is parsing a JSON string into a Python dictionary. Use json.loads() (load-string):
import json
json_string = '{"name": "Alice", "age": 30, "active": true}'
data = json.loads(json_string)
print(data["name"]) # Alice
print(data["age"]) # 30
print(type(data)) # <class 'dict'> The JSON-to-Python type mapping is intuitive:
| JSON Type | Python Type |
|---|---|
object {} | dict |
array [] | list |
| string | str |
| number (int) | int |
| number (float) | float |
| true / false | True / False |
| null | None |
Reading JSON from a File with json.load()
Note the function name difference: json.load() (no "s") reads from a file object, while json.loads() parses a string.
import json
with open("config.json", "r") as f:
config = json.load(f)
print(config["database"]["host"]) # localhost Always use a with statement to ensure the file handle is properly closed, even if parsing fails.
Parsing JSON from an API Response
When working with APIs using the requests library, you don't need to call json.loads() manually — the response object has a built-in .json() method:
import requests
response = requests.get("https://api.example.com/users/1")
user = response.json()
print(user["name"])
print(user["email"]) Under the hood, response.json() calls json.loads(response.text) and handles encoding detection automatically.
Converting Python Objects to JSON
The reverse operation uses json.dumps() (dump-string) and json.dump() (dump to file):
import json
data = {
"name": "Bob",
"scores": [95, 87, 92],
"active": True,
"address": None
}
# To string
json_string = json.dumps(data, indent=2)
print(json_string)
# To file
with open("output.json", "w") as f:
json.dump(data, f, indent=2) The indent parameter controls pretty-printing. Use indent=2 or indent=4 for readable output, or omit it for compact single-line JSON.
Handling Common Parsing Errors
Invalid JSON raises a json.JSONDecodeError. Always wrap parsing in a try/except block when handling untrusted input:
import json
def safe_parse(json_string):
try:
return json.loads(json_string)
except json.JSONDecodeError as e:
print(f"Invalid JSON at line {e.lineno}, column {e.colno}: {e.msg}")
return None
# Common mistakes that cause errors:
safe_parse("{name: 'Alice'}") # Keys must be double-quoted
safe_parse("{'name': 'Alice'}") # Must use double quotes, not single
safe_parse('{"age": 030}') # No leading zeros on numbers
safe_parse('{"items": [1, 2,]}') # No trailing commas Working with Nested JSON
Real-world JSON is often deeply nested. Access values by chaining keys, and use .get() for safe access:
import json
response = '''{
"data": {
"users": [
{"id": 1, "name": "Alice", "address": {"city": "Portland"}},
{"id": 2, "name": "Bob", "address": null}
]
}
}'''
data = json.loads(response)
# Direct access (raises KeyError if missing)
city = data["data"]["users"][0]["address"]["city"]
print(city) # Portland
# Safe access with .get() and defaults
for user in data["data"]["users"]:
address = user.get("address") or {}
city = address.get("city", "Unknown")
print(f"{user['name']}: {city}") Parsing Large JSON Files Efficiently
For very large JSON files (hundreds of MB), loading the entire file into memory may not be practical. Use ijson for streaming/iterative parsing:
# pip install ijson
import ijson
with open("large_data.json", "rb") as f:
# Parse items from a JSON array one at a time
for item in ijson.items(f, "records.item"):
process(item) # Only one item in memory at a time For moderately large files (10-100 MB), the built-in json module is usually fine — it's implemented in C and is quite fast.
Custom JSON Encoding and Decoding
Python's json module can't serialize all Python types by default. Dates, sets, and custom objects need a custom encoder:
import json
from datetime import datetime, date
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
if isinstance(obj, set):
return list(obj)
return super().default(obj)
data = {
"created": datetime.now(),
"tags": {"python", "json", "tutorial"}
}
print(json.dumps(data, cls=CustomEncoder, indent=2)) Performance Tips
- Use
orjsonfor speed — it's 3-10x faster than the standard library for both parsing and serialization. Install withpip install orjson. - Avoid repeated parsing — parse once and pass the dictionary around, don't re-parse the same string.
- Use
json.loads()overeval()— never useeval()to parse JSON. It's a serious security vulnerability that allows arbitrary code execution. - Validate before processing — use a JSON validator to check your data structure during development.
Quick Reference
| Operation | Method |
|---|---|
| String to dict | json.loads(string) |
| File to dict | json.load(file_obj) |
| Dict to string | json.dumps(dict) |
| Dict to file | json.dump(dict, file_obj) |
| Pretty print | json.dumps(dict, indent=2) |
| Sort keys | json.dumps(dict, sort_keys=True) |
JSON parsing in Python is one of those things that's simple 90% of the time and tricky the other 10%. Master the basics covered here, and you'll handle the tricky parts when they come. For quick formatting and validation during development, try our JSON Formatter to instantly beautify and check your JSON output.