• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

Justin Joyce

Practical tips and tutorials about software development.

  • Standing Invitation
  • Featured Posts
  • Latest
  • About

JSON in Python

Posted Aug 13, 2023 โ€” Updated Jan 10, 2024

Working with JSON in Python relies on Python’s builtin json module. After you import json, here are the json module methods:

  1. json.loads – deserialize a json string into the appropriate Python type(s)
  2. json.dumps – serialize a Python “object” into a json string
  3. json.load – deserialize json from a file
  4. json.dump – serialize json into a file

Notice that the methods ending in “s” deal directly with strings, whereas the others deal with files. To disambiguate them, I call them “load string” and “dump string” (in my own head, at least).

json.loads (load string)

Use this when you need to deserialize a json string, like when handling a json API response:

import json

person_str = '{"name": "justin", "age": 100}'
person_dict = json.loads(person_str)

print(person_dict)
{"name": "justin", "age": 100}

Default value parsing

Python json.load and json.loads also provide some nice keyword argument hooks for loading json data: parse_float, parse_int, and parse_constant. Each of these is called on its specified data type during loading, and the result of the hook function is what comes out at the end. Let’s do a quick example.

Say you know that all the float values in a json payload need to be converted to Decimal type. We can do that easily with parse_float:

import json, decimal

person_str = '{"name": "justin", "dollars": 50.25}'

json.loads(person_str, parse_float=decimal.Decimal)
# {"name": "justin", "dollars": Decimal("50.25")}

The other parse_ methods work just like this. There’s even an object_hook you can call on the full decoded payload, to be used like a reducer. For more, see the official docs.

json.dumps (dump string)

Using the same person from above:

import json

person = {"name": "justin", "age": 100}
json.dumps(person)
'{"name": "justin", "age": 100}'

With pretty printing

For nicer formatting, you might want to pretty-print your json:

import json

person = {"name": "justin", "age": 100}

# use the indent kwarg for nicer formatting
print(json.dumps(person, indent=4))
{
    "name": "justin",
    "age": 100
}

You can also sort the keys of your json, which makes life easier when inspecting large json objects:

import json

person = {"name": "justin", "age": 100}

# use the sort_keys kwarg to sort object keys
print(json.dumps(person, indent=4, sort_keys=True))
{
	"age": 100,
	"name": "justin"
}

These pretty-printing and formatting kwargs work exactly the same in json.dump also.

json.dump (to file)

This works just like json.dumps, but instead of writing to a string it writes to a file:

import json

person = {"name": "justin", "age": 100}

with open("person_file.json", "w") as outfile:
	person = json.dump(person, outfile)

json.load (from file)

This works just like json.loads above, but instead of acting on a string it reads from a file:

import json

# read the file we just created above
with open("person_file.json", "r") as infile:
	person = json.load(infile)
    
print(person)
# {"name": "justin", "age": 100}

Type conversions

Converting Python into json is not 100% apples to apples. Tuples become arrays1, None isn’t valid json, True and False aren’t capitalized, etc. Here’s the conversion table lifted directly from the Python json docs:

JSONPython
objectdict
arraylist
stringstr
number (int)int
number (real)float
trueTrue
falseFalse
nullNone

Errors when reading or writing json

If you try and load something that isn’t json, or isn’t properly encoded, you’ll see either a TypeError or a JSONDecodeError:

import json

# This is a dict, not JSON
json.loads({"name": "justin"})
# TypeError: the JSON object must be str, bytes or bytearray, not dict

# This string has an extra " in it, it's not properly encoded
json.loads('{"name": "justin""}')
# JSONDecodeError: Extra data: line 1 column 19 (char 18)

Gotcha: Decimal type

There is a small note in the official docs about “exotic” numerical types, like decimal.Decimalโ€”they are not JSON serializable:

import json
import decimal

not_serializable = {"number": decimal.Decimal(100)}
json.dumps(not_serializable)
# TypeError: Object of type Decimal is not JSON serializable

You can use json.dumps default keyword argument to get around this issue, it provides a default encoding function to be used for data that could not be serialized. In the case of the Decimal above, we could pass float:

import json, decimal

not_serializable = {"number": decimal.Decimal(100)}
json.dumps(not_serializable, default=float)
'{"number": 100.0}'

Careful with default though, it will apply to all non-serializable Python types. If you tried to use float and there was a datetime object in your data, you’d get a new error2.


  1. json doesn’t have a tuple type, so Python tuples become json arrays โ†ฉ๏ธŽ
  2. This blog post has a clever default encoding solution using python f-strings โ†ฉ๏ธŽ

Filed Under: Python

Primary Sidebar

Recent Posts

  • Every Built-In Vim Color Scheme (with screenshots)
  • Reverse a string in Python
  • Meeting Cost Calculator
  • Vim find and replace
  • What makes an effective development team

Categories

  • Arrays (5)
  • Command Line (9)
  • Dates (3)
  • Featured (7)
  • Git (7)
  • Golang (5)
  • Javascript (8)
  • Productivity (8)
  • Projects (4)
  • Python (15)
  • Regex (2)
  • Ruby (3)
  • Shell (2)
  • Thoughts (2)
  • Tips (11)
  • Tools (3)
  • Tutorials (1)
  • Vim (4)

Archives

  • July 2024 (1)
  • February 2024 (1)
  • January 2024 (1)
  • December 2023 (1)
  • November 2023 (1)
  • October 2023 (4)
  • September 2023 (1)
  • August 2023 (2)
  • July 2023 (5)
  • June 2023 (3)
  • May 2023 (6)
  • April 2023 (5)
  • March 2023 (5)
  • February 2023 (10)
  • January 2023 (6)
  • December 2022 (7)

Copyright © 2025 ยท Contact me at justin [at] {this domain}

  • Privacy Policy