Use object_hook to construct a tiny value object
Also published in our primary archive.
To use object_hook to construct a tiny value object safely, recognize one narrow tagged shape and return ordinary dictionaries for everything else. The hook is invoked for every JSON object decoded. The fixture includes a tagged point plus an unrelated metadata dictionary that happens to have x and y members. A broad hook based only on coordinate names would transform that unrelated payload too.
The first decode shows the default Python value. point_hook then requires exactly three keys, a kind value of point, and integer coordinates before constructing the frozen Point dataclass. The assertions show both sides of the boundary: shape becomes Point(2, 3), while metadata remains a dictionary. Its generated dataclass representation is deterministic for this simple class.
An object_hook is a transformation mechanism, not a complete document schema validator. It receives each decoded object independently, so a richer input contract should validate the returned tree separately. The tag is also only a data convention; it does not authenticate the payload. This example requires Python 3.7+ because it uses dataclasses; json.loads(..., object_hook=...) is older.
AI assistance disclosure: this article was drafted with AI and uses a synthetic JSON string.
Source: Python json documentation.
import json
from dataclasses import dataclass
@dataclass(frozen=True)
class Point:
x: int
y: int
def point_hook(mapping):
if (
set(mapping) == {"kind", "x", "y"}
and mapping["kind"] == "point"
and type(mapping["x"]) is int
and type(mapping["y"]) is int
):
return Point(mapping["x"], mapping["y"])
return mapping
text = '{"shape":{"kind":"point","x":2,"y":3},"metadata":{"x":2,"y":3}}'
default_decoded = json.loads(text)
hooked_decoded = json.loads(text, object_hook=point_hook)
assert hooked_decoded["shape"] == Point(2, 3)
assert hooked_decoded["metadata"] == {"x": 2, "y": 3}
print(text)
print(default_decoded)
print(hooked_decoded)
print(f"hook constructs {hooked_decoded['shape']} only when kind equals point")
{"shape":{"kind":"point","x":2,"y":3},"metadata":{"x":2,"y":3}}
{'shape': {'kind': 'point', 'x': 2, 'y': 3}, 'metadata': {'x': 2, 'y': 3}}
{'shape': Point(x=2, y=3), 'metadata': {'x': 2, 'y': 3}}
hook constructs Point(x=2, y=3) only when kind equals point