Master JSON in Python: From Basics to Advanced Custom Encoders
This tutorial walks through Python's built‑in json module, covering import, core concepts, serialization and deserialization of simple and complex structures, file I/O, and how to create custom JSONEncoder and JSONDecoder classes for advanced use cases.
Introduction
JSON (JavaScript Object Notation) is a lightweight data‑exchange format that is easy for humans to read and write and easy for machines to parse and generate. Python includes the built‑in json module for handling JSON data.
Importing the json module
import jsonBasic JSON concepts
Objects correspond to Python dict objects and are written with {}. Arrays correspond to Python list objects and are written with []. A key‑value pair consists of a string key and a value, which may be a string, number, object, array, boolean, or null.
Serializing Python objects (JSON encoding)
Use json.dumps() to convert a Python object into a JSON‑formatted string. The indent argument produces pretty‑printed output.
import json
data = {
"name": "Alice",
"age": 30,
"is_student": False,
"courses": ["Math", "Science"],
"address": {"street": "123 Main St", "city": "Anytown"}
}
json_string = json.dumps(data, indent=4)
print(json_string)Deserializing JSON strings (JSON decoding)
Use json.loads() to parse a JSON string back into a Python object.
json_string = '''
{
"name": "Alice",
"age": 30,
"is_student": false,
"courses": ["Math", "Science"],
"address": {"street": "123 Main St", "city": "Anytown"}
}
'''
data = json.loads(json_string)
print(data)Reading and writing JSON files
The json.load() and json.dump() functions operate on file objects.
# Read JSON from a file
with open('data.json', 'r') as file:
data = json.load(file)
print(data)
# Write JSON to a file
with open('data.json', 'w') as file:
json.dump(data, file, indent=4)Handling complex JSON structures
When JSON contains nested objects and arrays, you can iterate recursively to process the data.
json_string = '''
{
"employees": [
{
"name": "John Doe",
"age": 30,
"department": "Sales",
"projects": [
{"name": "Project A", "status": "Completed"},
{"name": "Project B", "status": "In Progress"}
]
},
{
"name": "Jane Smith",
"age": 28,
"department": "Marketing",
"projects": [
{"name": "Project C", "status": "Not Started"},
{"name": "Project D", "status": "Completed"}
]
}
]
}
'''
data = json.loads(json_string)
for employee in data['employees']:
print(f"Name: {employee['name']}")
print(f"Age: {employee['age']}")
print(f"Department: {employee['department']}")
print("Projects:")
for project in employee['projects']:
print(f" - {project['name']} ({project['status']})")
print()Custom JSON encoder and decoder
Subclass json.JSONEncoder to define how non‑standard types (e.g., datetime) are converted to JSON, and subclass json.JSONDecoder to reconstruct them.
import json
from datetime import datetime
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
data = {"name": "Alice", "date": datetime.now()}
json_string = json.dumps(data, cls=CustomEncoder, indent=4)
print(json_string)
class CustomDecoder(json.JSONDecoder):
def __init__(self, *args, **kwargs):
super().__init__(object_hook=self.object_hook, *args, **kwargs)
def object_hook(self, dct):
if 'date' in dct:
dct['date'] = datetime.fromisoformat(dct['date'])
return dct
json_string = '{"name": "Alice", "date": "2023-10-29T14:30:00.000000"}'
obj = json.loads(json_string, cls=CustomDecoder)
print(obj)Extending json for custom classes
Define to_dict and from_dict methods on your own classes, then use a custom encoder/decoder to serialize and deserialize nested custom objects.
# Example custom classes (Person, Address) with to_dict/from_dict omitted for brevity.
# Use CustomEncoder and CustomDecoder as shown above to handle them.Conclusion
The json module comfortably handles everything from simple dictionaries to deeply nested structures. By creating custom JSONEncoder and JSONDecoder subclasses, developers can extend JSON handling to arbitrary Python objects, making data exchange both flexible and maintainable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
