Python JSON: Encoding, Decoding, and File Handling – A Practical Guide
What is JSON in Python?
JSON—short for JavaScript Object Notation—is the most widely used text‑based data interchange format. In Python it maps directly to native data structures: objects become dicts, arrays become lists, strings, numbers, booleans, and null translate to str, int/float, bool, and None respectively. The json module in the standard library handles all conversions.
JSON Library in Python
Import the module once in your script:
import json
The module offers four core methods:
| Method | Description |
|---|---|
| dumps() | Convert a Python object to a JSON string. |
| dump() | Write a JSON string directly to a file object. |
| loads() | Parse a JSON string into a Python object. |
| load() | Read and parse a JSON file into a Python object. |
Python to JSON (Encoding)
Encoding is the process of converting Python data types into JSON. The default mapping is shown below:
| Python | JSON |
|---|---|
| dict | Object |
| list | Array |
| str/unicode | String |
| int/long | Number (int) |
| float | Number (real) |
| True | true |
| False | false |
| None | null |
Example using json.dumps():
import json
x = {
"name": "Ken",
"age": 45,
"married": True,
"children": ("Alice", "Bob"),
"pets": ["Dog"],
"cars": [
{"model": "Audi A1", "mpg": 15.1},
{"model": "Zeep Compass", "mpg": 18.1}
]
}
# Pretty‑print with sorted keys
sorted_string = json.dumps(x, indent=4, sort_keys=True)
print(sorted_string)
Output:
{
"age": 45,
"cars": [
{
"model": "Audi A1",
"mpg": 15.1
},
{
"model": "Zeep Compass",
"mpg": 18.1
}
],
"children": [
"Alice",
"Bob"
],
"married": true,
"name": "Ken",
"pets": [
"Dog"
]
}
Writing a JSON object to a file is straightforward with json.dump():
with open('json_file.json', 'w') as file_write:
json.dump(x, file_write, indent=4, sort_keys=True)
After running the script, json_file.json will contain the serialized data.
JSON to Python (Decoding)
Decoding reverses the mapping, turning a JSON string or file back into native Python objects. The conversion table mirrors the encoding table:
| JSON | Python |
|---|---|
| Object | dict |
| Array | list |
| String | str |
| Number (int) | int |
| Number (real) | float |
| true | True |
| false | False |
| null | None |
Example using json.loads():
import json
person_data = '{"person": {"name": "Kenn", "sex": "male", "age": 28}}'
obj = json.loads(person_data)
print(obj)
print(type(obj))
print(obj.get('person'))
Output:
{'person': {'name': 'Kenn', 'sex': 'male', 'age': 28}}
<class 'dict'>
{'name': 'Kenn', 'sex': 'male', 'age': 28}
Reading a JSON file directly:
with open('json_file.json') as f:
data = json.load(f)
print(data)
Output:
{'name': 'Ken', 'age': 45, ...}
Compact and Pretty‑Print Encoding
For network transmission, compact encoding removes whitespace:
lst = ['a', 'b', 'c', {"4": 5, "6": 7}]
compact = json.dumps(lst, separators=(',', ':'))
print(compact)
Output:
["a","b","c",{"4":5,"6":7}]
For human readability, pretty‑printing uses indentation:
dic = {"a": 4, "b": 5}
pretty = json.dumps(dic, indent=4, separators=(',', ': '))
print(pretty)
Output:
{
"a": 4,
"b": 5
}
Encoding Complex Objects
The json module cannot serialize arbitrary objects. To handle a complex number, supply a default function:
def complex_encode(o):
if isinstance(o, complex):
return [o.real, o.imag]
raise TypeError(f"{repr(o)} is not JSON serializable")
print(json.dumps(4 + 5j, default=complex_encode))
Output:
[4.0, 5.0]
Decoding Complex Objects
Use object_hook to detect a custom marker and rebuild the complex number:
def is_complex(obj):
if "__complex__" in obj:
return complex(obj["real"], obj["img"])
return obj
complex_obj = json.loads('{"__complex__": true, "real": 4, "img": 5}', object_hook=is_complex)
print(complex_obj)
Output:
(4+5j)
Serialization & Deserialization Classes
The JSONEncoder and JSONDecoder classes provide fine‑grained control:
JSONEncoder.default(o)– override to serialize custom objects.JSONEncoder.encode(o)– return a JSON string.JSONEncoder.iterencode(o)– iterate over the output string.JSONDecoder.decode(s)– parse a JSON string.JSONDecoder.raw_decode(s)– parse starting at a given index.
Example:
from json.encoder import JSONEncoder
print(JSONEncoder().encode({"colour": ["red", "yellow", "green"]}))
Fetching JSON from a URL
Using requests to download a live JSON feed (e.g., CityBike NYC):
import json, requests
response = requests.get("https://feeds.citibikenyc.com/stations/stations.json")
bike_dict = json.loads(response.text)
print(bike_dict['stationBeanList'][0])
Output:
{
'id': 487,
'stationName': 'E 20 St & FDR Drive',
'availableDocks': 24,
...
}
Handling JSON Exceptions
The primary exception is json.JSONDecodeError, a subclass of ValueError. Example handling:
try:
with open('bad.json') as f:
data = json.load(f)
except json.JSONDecodeError as e:
print(f"Bad JSON: {e}")
Special Numeric Values
RFC 8259 does not allow Infinity or NaN, but the Python encoder represents them as strings:
print(json.dumps(float('inf')))
print(json.dumps(float('nan')))
Output:
Infinity NaN
Repeated Keys in JSON
When a key appears multiple times, Python’s json.loads() keeps only the last occurrence:
json.loads('{"a": 1, "a": 2, "a": 3}')
# -> {'a': 3}
Command‑Line Tools
The json.tool module formats and validates JSON from the command line:
$ echo '{"name": "Kings Arthur"}' | python3 -m json.tool
{
"name": "Kings Arthur"
}
Advantages of JSON in Python
- Native support via the
jsonmodule. - Human‑readable with pretty‑printing.
- Widely adopted for APIs, configuration, and data storage.
- Language‑agnostic and lightweight.
Limitations
- Does not support custom data types without a custom encoder.
- Maximum recursion depth limits deeply nested structures.
- Large documents can be memory intensive to load fully.
Python JSON Cheat Sheet
| Function | Description |
|---|---|
| json.dumps(obj) | Serialize Python object to JSON string. |
| json.dump(obj, file) | Write JSON string to a file. |
| json.dumps(obj, separators=(",", ":")) | Compact representation without spaces. |
| json.dumps(obj, indent=4) | Pretty‑printed JSON with indentation. |
| json.dumps(obj, sort_keys=True) | Sort dictionary keys alphabetically. |
| json.dumps(obj, default=custom) | Encode unsupported objects. |
| JSONEncoder().encode(obj) | Manual serialization via encoder class. |
| json.loads(s) | Parse JSON string to Python object. |
| json.loads(s, object_hook=custom) | Custom deserialization logic. |
| JSONDecoder().decode(s) | Manual deserialization via decoder class. |
Python
- Python File I/O: Mastering File Operations, Reading, Writing, and Management
- Master Python File Handling: Create, Read, Write, and Open Text Files with Ease
- Checking File and Directory Existence in Python – A Practical Guide
- Copy Files in Python with shutil.copy() and shutil.copystat()
- How to Rename Files and Directories in Python with os.rename() – Step-by-Step Guide
- Creating ZIP Archives in Python: From Full Directory to Custom File Selection
- Mastering Python’s readline() – Efficient Line‑by‑Line File Reading
- How to Read and Write CSV Files in Python: A Comprehensive Guide
- Master XML Parsing in Python: A Practical Guide Using Minidom and ElementTree
- Python File I/O: Mastering Input and Output Operations