How to Parse JSON in Python (json.loads vs json.load)
Parsing JSON in Python is mostly about knowing which of two functions to call, and then handling the errors when the input is not what you expected. The standard library ships a json module, so there is nothing to install. This guide covers json.loads versus json.load, reading JSON from files and API responses, catching parse errors cleanly, and the type conversions that surprise people coming from other languages.
The two functions you need
Python’s json module gives you two ways to read JSON, and the only real difference is where the data comes from.
json.loads(s)parses JSON from a string (thesstands for string).json.load(f)parses JSON from a file-like object (anything with a.read()method).
That one letter is the entire distinction, and mixing them up is the most common beginner mistake. If you have text, use loads. If you have an open file, use load.
import json
# From a string
data = json.loads('{"name": "Ada", "age": 36}')
print(data["name"]) # Ada
# From a file
with open("person.json") as f:
data = json.load(f)
print(data["age"]) # 36
Both return ordinary Python objects. A JSON object becomes a dict, a JSON array becomes a list, and from there you access values with normal indexing.
Reading JSON from a file
For files, json.load with a context manager is the idiomatic pattern. The with block closes the file for you even if parsing raises.
import json
with open("config.json", encoding="utf-8") as f:
config = json.load(f)
print(config["database"]["host"])
Always pass encoding="utf-8" when opening the file. JSON is defined as UTF-8, and relying on the platform default encoding is a common source of hard-to-reproduce bugs on Windows. If you are not sure the file is even valid JSON yet, it helps to open it in a JSON viewer first so you can see the structure as a collapsible tree before you write code against it. Our guide on how to open a JSON file covers the non-code options.
Parsing JSON from an API response
Most real parsing happens on data that arrives over HTTP. If you use the requests library, it has a .json() method that calls json.loads on the response body for you.
import requests
resp = requests.get("https://api.example.com/users/1")
user = resp.json() # already parsed into a dict
print(user["email"])
If you are using the standard library instead of requests, you read the body and parse it yourself. Note that urllib gives you bytes, and json.loads happily accepts bytes as well as str:
import json
from urllib.request import urlopen
with urlopen("https://api.example.com/users/1") as resp:
user = json.loads(resp.read())
print(user["email"])
Either way, treat the response as untrusted. An API can return an error page, an empty body, or malformed JSON, so wrap the parse in error handling rather than assuming it will succeed.
Handling parse errors
When the input is not valid JSON, both functions raise json.JSONDecodeError, which is a subclass of ValueError. Catch it and you get the message, line, and column of the problem.
import json
raw = '{"name": "Ada", }' # trailing comma, invalid JSON
try:
data = json.loads(raw)
except json.JSONDecodeError as e:
print(f"Invalid JSON: {e.msg} at line {e.lineno} column {e.colno}")
The trailing comma above is one of the most frequent causes of failure, because it is legal in Python dicts but not in JSON. If you are staring at an error and cannot see what is wrong, paste the text into the JSON parser; it points to the exact character that breaks the parse, which is faster than reading a stack trace. Two errors come up so often they have their own write-ups: the Unexpected token error and, more broadly, understanding what valid JSON looks like in the first place.
How JSON types map to Python
Parsing converts JSON types into their Python equivalents. Most are obvious, but a few catch people out.
| JSON | Python |
|---|---|
| object | dict |
| array | list |
| string | str |
| number (int) | int |
| number (float) | float |
true / false |
True / False |
null |
None |
The ones that bite: JSON null becomes None, not an empty string, so checking if value is None is the correct test. JSON has a single number type, but Python splits it into int and float based on whether there is a decimal point, so 1 parses to int and 1.0 to float. And object keys are always strings in JSON, so even {"1": "a"} gives you a dict keyed by the string "1", not the integer 1.
Going the other way: writing JSON
The reverse of parsing is serializing, and it mirrors the two-function pattern. json.dumps(obj) returns a JSON string, and json.dump(obj, f) writes JSON to a file.
import json
data = {"name": "Ada", "roles": ["admin", "dev"]}
# To a string, nicely indented
text = json.dumps(data, indent=2)
# To a file
with open("out.json", "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
Two options are worth knowing. indent=2 pretty-prints the output, which is the programmatic equivalent of running it through an online JSON formatter. And ensure_ascii=False keeps non-ASCII characters readable instead of escaping them to \uXXXX, which matters for any non-English text. For the opposite goal, leaving both off produces the most compact output, the same result you would get from a JSON minifier.
A few practical tips
- Parse once, pass the object around. Do not re-parse the same string in multiple places. Parse it at the boundary of your program and work with the resulting dict or list.
- Validate the shape, not just the syntax.
json.loadstells you the JSON is well-formed, not that it contains the keys you expect. Usedata.get("key")to avoid aKeyErroron missing fields. - Watch out for duplicate keys. JSON technically allows duplicate object keys, and Python keeps the last one silently. If that matters, pass an
object_pairs_hookto detect it. - Large files. The standard
jsonmodule loads the whole document into memory. For very large files, a streaming parser likeijsonprocesses the file incrementally.
Frequently asked questions
What is the difference between json.loads and json.load in Python?
json.loads parses JSON from a string, while json.load reads and parses JSON from a file-like object. The s in loads stands for string. Use loads for text you already have in memory, and load for an open file.
How do I fix a JSONDecodeError?
The exception tells you the line and column of the problem. The usual causes are a trailing comma, single quotes instead of double quotes, or an unquoted key, none of which are valid JSON. Run the text through the JSON parser to see the exact spot it fails.
How do I parse JSON from a requests response?
Call .json() on the response object, for example requests.get(url).json(). That runs json.loads on the body and returns a Python dict or list. Wrap it in a try/except json.JSONDecodeError in case the server returns a non-JSON body.
Does parsing JSON in Python need an external library?
No. The json module is part of the Python standard library, so import json works with no installation. Third-party libraries like orjson are faster for high-throughput workloads, but the built-in module covers almost every case.
Once you have parsed your data, the rest of the toolkit helps you work with it: format or validate it in the JSON formatter, convert it to a spreadsheet with JSON to CSV, or browse the full set of free JSON tools.
Leave a Reply