Fundamentals 11 min read

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.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Master JSON in Python: From Basics to Advanced Custom Encoders

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 json

Basic 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Pythondata-processingserializationJSONDeserializationfile-iocustom-encoder
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.