Skip to content

JSON Module Complexity

The json module provides JSON serialization and deserialization.

Functions

Function Time Space Notes
json.dumps(obj) O(n) O(n) Serialize to string
json.dump(obj, fp) O(n) O(d) d = nesting depth; writes incrementally
json.loads(s) O(n) O(n) Parse JSON string
json.load(fp) O(n) O(n) Reads full file into memory
JSONEncoder.encode() O(n) O(n) Custom encoder
JSONDecoder.decode() O(n) O(n) Custom decoder

Serialization (dumps/dump)

Time Complexity: O(n)

Where n = total number of elements and size of strings in object tree.

import json

# Simple object: O(n) where n = 3
data = {'a': 1, 'b': 2, 'c': 3}
json_str = json.dumps(data)  # O(3)

# Nested object: O(n) where n = total elements
data = {
    'users': [
        {'name': 'Alice', 'age': 30},
        {'name': 'Bob', 'age': 25},
    ],
    'count': 2
}
json_str = json.dumps(data)  # O(n) for all elements

Space Complexity: O(n)

import json

# Memory usage proportional to output size
data = {'key': 'x' * 1000000}
json_str = json.dumps(data)  # O(n) - creates large string
# JSON includes: {"key":"xxx..."}
# Size ~ data size + quotes + braces

Deserialization (loads/load)

Time Complexity: O(n)

import json

# Parsing JSON string: O(n) where n = string length
json_str = '{"key": "value", "num": 123}'
data = json.loads(json_str)  # O(n)

# Large JSON: O(n)
large_json = json.dumps({'data': [i for i in range(10000)]})
data = json.loads(large_json)  # O(n)

Space Complexity: O(n)

import json

# Creates Python objects taking O(n) space
json_str = '{"items": [1, 2, 3, ..., 10000]}'
data = json.loads(json_str)  # O(n) memory for result

File I/O

dump() - Write to File

import json

# Write to file: O(n) for serialization + file I/O
data = {'key': 'value', 'items': list(range(1000))}

with open('data.json', 'w') as f:
    json.dump(data, f)  # O(n) serialization + write

# Streaming: O(d) extra memory, O(n) time (object itself still in memory)
# Writes to file incrementally

load() - Read from File

import json

# Read from file: O(n) for parsing
with open('data.json', 'r') as f:
    data = json.load(f)  # O(n) parse time, O(n) memory

Custom Encoders/Decoders

JSONEncoder

import json
from datetime import datetime

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):  # O(1) per call
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

# Use custom encoder: O(n) + O(1) per custom object
data = {'timestamp': datetime.now()}
json_str = json.dumps(data, cls=DateTimeEncoder)  # O(n)

JSONDecoder

import json
from datetime import datetime

def datetime_parser(dct):  # O(1) per call
    for key, val in dct.items():
        if isinstance(val, str):
            try:
                dct[key] = datetime.fromisoformat(val)
            except (ValueError, TypeError):
                pass
    return dct

# Use custom decoder: O(n) + O(1) per custom object
json_str = '{"timestamp": "2024-01-12T12:00:00"}'
data = json.loads(json_str, object_hook=datetime_parser)  # O(n)

Performance Characteristics

Best Practices

import json

# Good: Single serialization
data = {'items': list(range(1000))}
json_str = json.dumps(data)  # O(n) once

# Bad: Multiple serializations
for i in range(100):
    json_str = json.dumps(data)  # O(n) * 100

# Good: Reuse encoder for large operations
encoder = json.JSONEncoder()
for i in range(100):
    json_str = encoder.encode(data)  # Still O(n) per iteration, but optimized

Memory Efficiency

import json

# Bad: Load entire large file into memory
with open('huge.json') as f:
    data = json.load(f)  # O(n) memory

# Better: Stream parsing (if available)
# or process line by line with JSONL format
with open('data.jsonl') as f:
    for line in f:
        obj = json.loads(line)  # O(1) per line

Common Patterns

Pretty Printing

import json

data = {'key': 'value', 'nested': {'a': 1, 'b': 2}}

# Normal: O(n)
json_str = json.dumps(data)

# Pretty printed: O(n) (same complexity, different format)
json_str = json.dumps(data, indent=2, sort_keys=True)

Custom Default Handler

import json

def custom_serializer(obj):  # O(1) per object
    if hasattr(obj, '__dict__'):
        return obj.__dict__
    raise TypeError(f"Object of type {type(obj)} is not JSON serializable")

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person('Alice', 30)
json_str = json.dumps(person, default=custom_serializer)  # O(n)

Version Notes

  • Python 3.x: json module is available

Common Issues

Large Files

import json

# Problem: Memory usage for large files
# Solution: Stream or use generators

def process_large_json(filename):
    with open(filename) as f:
        # If it's a list, could parse item by item
        # Or use JSONL format (one JSON object per line)
        for line in f:
            obj = json.loads(line)
            yield obj

Circular References

import json

# This will fail with circular reference
a = {'name': 'A'}
b = {'name': 'B', 'ref': a}
a['ref'] = b  # Circular!

json.dumps(a)  # ValueError: Circular reference detected