Working with JSON0%

Working with JSON

Beginner12 min readUpdated: Jul 11, 2026
Study Materials

Working with JSON: Advanced Serialization

JavaScript Object Notation (JSON) is the lingua franca of modern web services, RESTful APIs, configuration files, and distributed microservice messaging. Standardized in RFC 8259, JSON is text-based, language-agnostic, and safe against arbitrary code execution.

While basic usage of Python's built-in json module is straightforward, enterprise applications require advanced techniques: custom JSON encoders for domain models, object_hook deserialization, high-density minification, and handling unsupported types like datetime, UUID, and Decimal.


1. Type Mappings & Limitations

Python and JSON share similar primitives, but their types do not map 1:1:

Python TypeJSON TypeNuance / Caveats
dictObjectJSON keys must be strings; integer dict keys {1: "a"} are coerced to {"1": "a"}
list, tupleArrayTuples serialize to JSON arrays and deserialize back as Python lists
strStringUTF-8 encoded
int, floatNumberJSON does not distinguish float vs int; NaN and Infinity are non-standard
True, Falsetrue, falseLowercase in JSON
NonenullLowercase in JSON
datetime, Decimal, UUIDTypeErrorUnsupported by default: requires custom encoder

2. Advanced Serialization with Custom JSONEncoder

When passing non-standard objects into json.dumps(), Python raises a runtime TypeError: Object of type X is not JSON serializable.

To handle complex domain entities, subclass json.JSONEncoder and override the default() method:

Visual Architecture & Process Flow

How data and code flow step-by-step

Flowchart
Step 1
def default
self, obj: Any
Step 2
Any:

3. Custom Deserialization with object_hook

When reading JSON via json.loads(), all objects become standard dictionaries. If you want JSON dictionaries to be deserialized directly into typed domain classes or parse ISO dates automatically, provide an object_hook:

Python
import datetime
import json
 
class UserProfile:
def __init__(self, username: str, email: str, last_login: str) -> None:
self.username = username
self.email = email
self.last_login = datetime.datetime.fromisoformat(last_login)
 
def __repr__(self) -> str:
return f"UserProfile({self.username!r}, last_login={self.last_login.strftime('%Y-%m-%d')})"
 
def user_object_hook(data: dict) -> Any:
"""Transforms raw dictionary into UserProfile if required keys are present."""
if "username" in data and "last_login" in data:
return UserProfile(
username=data["username"],
email=data["email"],
last_login=data["last_login"]
)
return data
 
raw_json = '{"username": "alovelace", "email": "ada@computing.org", "last_login": "2026-09-12T10:15:30"}'
 
# Deserialize using object_hook
profile = json.loads(raw_json, object_hook=user_object_hook)
print(f"Deserialized Type: {type(profile).__name__}")
print(f"Object details: {profile}")

4. Formatting: Minification vs Pretty-Printing

JSON formatting parameters allow you to optimize for human readability or network bandwidth:

Python
data = {"service": "gateway", "status": "UP", "nodes": [1, 2, 3]}
 
# 1. Pretty-Printing for Debugging & Logs (indent=2 or 4)
pretty_json = json.dumps(data, indent=2)
print("Pretty JSON:\n", pretty_json)
 
# 2. Maximum Minification for Wire Transfer (removes whitespace around separators)
# separators=(item_separator, key_separator)
minified_json = json.dumps(data, separators=(",", ":"))
print("Minified JSON Wire Format:", minified_json)
 
# 3. Deterministic Hashing / Signature Verification (sort_keys=True)
# Guarantees identical string representation regardless of dictionary insertion order
canon_json = json.dumps(data, sort_keys=True, separators=(",", ":"))
print("Canonical JSON String: ", canon_json)

5. Architectural Summary Table

ParameterFunctionPurpose
cls=CustomEncoderjson.dumps()Plugs in custom class to serialize arbitrary object types
object_hook=funcjson.loads()Intercepts dictionary parsing to instantiate custom objects
indent=Njson.dumps()Indents JSON with $N$ spaces for readability
separators=(",", ":")json.dumps()Strips unnecessary whitespace for minified network payload
sort_keys=Truejson.dumps()Sorts dictionary keys alphabetically for deterministic output

Multiple Choice Questions

1.

What exception is raised when calling json.dumps({"time": datetime.datetime.now()}) without a custom serializer? A. ValueError B. TypeError: Object of type datetime is not JSON serializable C. KeyError D. SerializationError

Answer: B
Explanation:The standard Python json library only supports basic primitives by default. Passing unsupported objects like datetime raises a TypeError.

2.

Which method must be overridden when creating a custom subclass of json.JSONEncoder? A. serialize(self, obj) B. default(self, obj) C. encode_object(self, obj) D. to_json(self, obj)

Answer: B
Explanation:In json.JSONEncoder, the default(self, obj) method is called for any object that the standard serializer cannot handle, allowing custom conversion into JSON-serializable types.

3.

What is the purpose of the object_hook parameter in json.loads()? A. To hook into the network socket. B. To intercept every parsed JSON object dictionary and optionally transform it into a custom Python class instance. C. To prevent JSON injection attacks. D. To validate schema types in SQLite.

Answer: B
Explanation:object_hook accepts a callable that is invoked with the result of any JSON object decoded as a dictionary, enabling automated conversion into custom domain objects.

4.

How can you produce the most compact, minified JSON string for transmission over a network socket? A. json.dumps(data, compress=True) B. json.dumps(data, separators=(",", ":")) C. json.dumps(data, indent=0) D. json.dumps(data, minified=True)

Answer: B
Explanation:Specifying separators=(",", ":") removes trailing spaces after commas and colons, producing a compact, minified wire payload.

5.

What happens to a Python tuple when it is serialized to JSON and then deserialized back to Python? A. It remains a tuple. B. It is converted into a list. C. It is converted into a set. D. It raises a ValueError.

Answer: B
Explanation:JSON does not have a distinct tuple type—only arrays. As a result, Python tuples serialize to JSON arrays and deserialize back into Python list objects.

Next Lesson

Working with YAML

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Previous LessonNext Lesson
Pickle ModuleWorking with YAML

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext