8 min read read
python jsonparse json pythonjson.loadsjson.loadpython tutorialjson file pythondeveloper toolscoding tutorial

How to Parse JSON in Python (With Examples)

Imad Uddin

Full Stack Developer

How to Parse JSON in Python (With Examples)

Working with JSON in Python is something you'll do constantly if you're building anything that talks to an API, reads configuration files, or processes data from the web. Python makes it ridiculously easy. The built-in

json
module handles everything you need, and you don't have to install anything extra.

I'll walk through exactly how to parse JSON in Python, starting from the basics and moving into the real world scenarios you'll actually encounter. Simple JSON strings, reading from files, handling messy nested data from an API response, error handling, it's all covered with runnable examples.

The Basics: json.loads() for Strings

The most common way to parse JSON in Python is using

json.loads()
. The "s" at the end stands for "string" because this function parses a JSON string and converts it into a Python dictionary (or list, depending on the JSON structure).

Here's the simplest possible example:

Python
import json

json_string = '{"name": "Alice", "age": 30, "city": "New York"}'

data = json.loads(json_string)

print(data)
print(data["name"])
print(data["age"])

Output:

{'name': 'Alice', 'age': 30, 'city': 'New York'}
Alice
30

That's it. The

json.loads()
function takes a string containing valid JSON and returns a Python dictionary. You can then access the values using standard dictionary syntax like
data["name"]
.

The JSON data types map to Python types automatically:

JSON TypePython Type
objectdict
arraylist
stringstr
number (int)int
number (float)float
trueTrue
falseFalse
nullNone

So if your JSON contains an array, you get a Python list. If it contains

null
, you get
None
. The conversion is intuitive and works the way you'd expect.

Reading JSON from a File: json.load()

When your JSON is in a file rather than a string, use

json.load()
(without the "s"). This function reads directly from a file object.

Python
import json

with open("config.json", "r") as file:
    data = json.load(file)

print(data)

The

with open()
pattern ensures the file is properly closed after reading. The
json.load()
function parses the entire file contents and returns the resulting Python object.

Here's what a typical

config.json
file might look like:

JSON
{
    "database": {
        "host": "localhost",
        "port": 5432,
        "name": "myapp"
    },
    "debug": true,
    "allowed_hosts": ["localhost", "127.0.0.1"]
}

And the Python code to read and use it:

Python
import json

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

db_host = config["database"]["host"]
db_port = config["database"]["port"]
debug_mode = config["debug"]

print(f"Connecting to {db_host}:{db_port}")
print(f"Debug mode: {debug_mode}")

Output:

Connecting to localhost:5432
Debug mode: True

Notice how you can access nested values by chaining the keys:

config["database"]["host"]
. This works because the outer value is itself a dictionary.

Handling JSON Arrays

Not all JSON starts with an object. Sometimes you'll get an array at the top level, especially when working with API responses that return lists of items.

Python
import json

json_string = '''
[
    {"id": 1, "name": "Product A", "price": 29.99},
    {"id": 2, "name": "Product B", "price": 49.99},
    {"id": 3, "name": "Product C", "price": 19.99}
]
'''

products = json.loads(json_string)

for product in products:
    print(f"{product['name']}: ${product['price']}")

Output:

Product A: $29.99
Product B: $49.99
Product C: $19.99

The

json.loads()
function returns a list in this case, and you can iterate over it normally. Each item in the list is a dictionary representing one product.

Error Handling: What Happens When JSON Is Invalid

If you try to parse invalid JSON, Python raises a

json.JSONDecodeError
. This is important to handle, especially when you're parsing data from external sources like APIs or user input where you can't guarantee the JSON is well-formed.

Python
import json

bad_json = '{"name": "Alice", "age": 30,}'  # trailing comma is invalid

try:
    data = json.loads(bad_json)
except json.JSONDecodeError as e:
    print(f"Failed to parse JSON: {e}")

Output:

Failed to parse JSON: Expecting property name enclosed in double quotes: line 1 column 32 (char 31)

The error message tells you exactly where the problem is: line 1, column 32. This is useful for debugging, especially with larger JSON documents.

A safer pattern for production code:

Python
import json

def safe_parse_json(json_string):
    try:
        return json.loads(json_string)
    except json.JSONDecodeError as e:
        print(f"Invalid JSON: {e}")
        return None

# Usage
data = safe_parse_json('{"valid": "json"}')
if data:
    print(data)

data = safe_parse_json('not json at all')
if data is None:
    print("Parsing failed, handle accordingly")

Wrapping the parse in a function with error handling makes your code more resilient. You can decide what to do when parsing fails: return

None
, raise a custom exception, log the error, or provide a default value.

Parsing JSON from an API Response

One of the most common real world uses when working with JSON in Python is parsing API responses. The

requests
library (which you'll need to install with
pip install requests
) returns a response object that has a built-in
.json()
method.

Python
import requests

response = requests.get("https://api.github.com/users/torvalds")

if response.status_code == 200:
    user_data = response.json()
    print(f"Name: {user_data['name']}")
    print(f"Location: {user_data['location']}")
    print(f"Public repos: {user_data['public_repos']}")
else:
    print(f"Request failed with status {response.status_code}")

The

response.json()
method is essentially a shortcut for
json.loads(response.text)
. It parses the response body as JSON and returns the resulting Python object.

Always check the status code before parsing. If the request fails (4xx or 5xx status), the response body might not be valid JSON, or it might be an error message in a different format.

Working with Nested JSON

Real world JSON is often deeply nested. API responses from services like Stripe, Twilio, or AWS can have multiple levels of nested objects and arrays. Knowing how to navigate this structure efficiently is important.

Here's an example of nested JSON you might get from a weather API:

Python
import json

weather_json = '''
{
    "location": {
        "city": "San Francisco",
        "country": "US",
        "coordinates": {
            "lat": 37.7749,
            "lon": -122.4194
        }
    },
    "current": {
        "temp": 62,
        "humidity": 75,
        "conditions": "Partly Cloudy"
    },
    "forecast": [
        {"day": "Monday", "high": 65, "low": 52},
        {"day": "Tuesday", "high": 68, "low": 54},
        {"day": "Wednesday", "high": 63, "low": 50}
    ]
}
'''

weather = json.loads(weather_json)

# Access nested object values
city = weather["location"]["city"]
lat = weather["location"]["coordinates"]["lat"]
current_temp = weather["current"]["temp"]

print(f"Current temperature in {city}: {current_temp}°F")
print(f"Latitude: {lat}")

# Iterate over nested array
print("\nForecast:")
for day in weather["forecast"]:
    print(f"  {day['day']}: High {day['high']}°F, Low {day['low']}°F")

Output:

Current temperature in San Francisco: 62°F
Latitude: 37.7749

Forecast:
  Monday: High 65°F, Low 52°F
  Tuesday: High 68°F, Low 54°F
  Wednesday: High 63°F, Low 50°F

The key is understanding that each level of nesting is just another dictionary or list access.

weather["location"]
gives you a dictionary.
weather["location"]["coordinates"]
gives you another dictionary inside that. You chain them together to reach the value you want.

Safely Accessing Nested Keys

When you're not sure if a key exists, accessing it directly will raise a

KeyError
. The
.get()
method lets you provide a default value instead.

Python
import json

data = json.loads('{"user": {"name": "Alice"}}')

# This will raise KeyError if "email" doesn't exist
# email = data["user"]["email"]

# Safe access with .get()
email = data["user"].get("email", "No email provided")
print(email)  # Output: No email provided

# For deeply nested access, check each level
location = data.get("user", {}).get("location", {}).get("city", "Unknown")
print(location)  # Output: Unknown

The pattern

data.get("key", {})
returns an empty dictionary if the key doesn't exist, which allows you to chain another
.get()
call without raising an error. This is useful when dealing with inconsistent API responses where some fields might be missing.

Parsing JSON with Custom Object Conversion

Sometimes you want to convert JSON directly into a custom Python class rather than a dictionary. The

json.loads()
function accepts an
object_hook
parameter for this purpose.

Python
import json

class User:
    def __init__(self, name, email, age):
        self.name = name
        self.email = email
        self.age = age
    
    def __repr__(self):
        return f"User({self.name}, {self.email}, {self.age})"

def user_decoder(obj):
    if "name" in obj and "email" in obj and "age" in obj:
        return User(obj["name"], obj["email"], obj["age"])
    return obj

json_string = '{"name": "Bob", "email": "bob@example.com", "age": 25}'

user = json.loads(json_string, object_hook=user_decoder)

print(user)
print(type(user))
print(user.name)

Output:

User(Bob, bob@example.com, 25)
<class '__main__.User'>
Bob

The

object_hook
function is called for every object (dictionary) in the JSON. If your decoder function recognizes the structure, it can return a custom object instead of the default dictionary. This is powerful for working with typed data structures.

Common Mistakes and How to Avoid Them

Mistake 1: Using json.load() on a string

Python
# Wrong
data = json.load('{"name": "Alice"}')  # TypeError

# Correct
data = json.loads('{"name": "Alice"}')  # Use loads() for strings

Remember:

load()
is for files,
loads()
is for strings.

Mistake 2: Forgetting that JSON keys must be strings

In Python dictionaries, keys can be integers, tuples, or other hashable types. In JSON, keys must always be strings.

Python
# This Python dict has an integer key
python_dict = {1: "one", 2: "two"}

# Converting to JSON will turn the key into a string
json_string = json.dumps(python_dict)
print(json_string)  # {"1": "one", "2": "two"}

# Parsing it back gives you string keys
parsed = json.loads(json_string)
print(parsed["1"])  # "one"
print(parsed[1])    # KeyError!

Mistake 3: Assuming the JSON structure without checking

API responses can change. Fields can be missing. Always validate or use safe access patterns.

Python
# Fragile code that assumes structure
name = data["user"]["profile"]["display_name"]

# Safer approach
name = data.get("user", {}).get("profile", {}).get("display_name", "Anonymous")

Performance Tip: Parsing Large JSON Files

If you're working with very large JSON files (hundreds of megabytes or more), loading the entire file into memory with

json.load()
can be slow or cause memory issues.

For large files, consider using

ijson
(install with
pip install ijson
), which parses JSON incrementally:

Python
import ijson

with open("large_file.json", "rb") as file:
    for item in ijson.items(file, "item"):
        process(item)  # Handle one item at a time

This streams through the file without loading it all into memory. It's more complex to use than

json.load()
, but it's necessary for files that are too large to fit in RAM.

For most everyday use cases, the standard

json
module is fast enough. Only reach for streaming parsers when you're actually hitting memory limits.

Quick Reference

Python
import json

# Parse JSON string to Python object
data = json.loads('{"key": "value"}')

# Parse JSON file to Python object
with open("file.json") as f:
    data = json.load(f)

# Convert Python object to JSON string
json_string = json.dumps(data)

# Write Python object to JSON file
with open("output.json", "w") as f:
    json.dump(data, f)

# Pretty print with indentation
json_string = json.dumps(data, indent=2)

# Handle parsing errors
try:
    data = json.loads(maybe_json)
except json.JSONDecodeError:
    print("Invalid JSON")

Wrapping Up

Parsing JSON in Python comes down to two functions for 99% of use cases:

json.loads()
for strings and
json.load()
for files. Once you have the data as a Python dictionary or list, you work with it using standard Python syntax.

The key things to remember:

  1. Import the
    json
    module (it's built in, no installation needed)
  2. Use
    loads()
    for strings,
    load()
    for files
  3. Wrap parsing in try/except when handling untrusted data
  4. Use
    .get()
    for safe access to keys that might not exist
  5. JSON objects become dictionaries, arrays become lists

That covers most of what you'll need for everyday JSON parsing in Python. The

json
module has more features for edge cases (custom encoders, strict parsing options, etc.), but the basics above will handle the vast majority of real world scenarios.

Related Guides

Need to validate your JSON before parsing? Check out the best online tools for validating JSON syntax.

Working with multiple JSON files? The JSON merger tool combines them directly in your browser.

How JSON Works explains the format itself if you want to understand the specification.

JSON vs XML vs YAML compares the three data formats if you're choosing between them for a project.

Read More

All Articles