python
41 lines · 6 steps
JSON round-tripping with Python dataclasses
A nested dataclass serializes itself to JSON and rebuilds from it, handling datetimes and nested objects along the way.
Explained by
highlit
1import json
2from dataclasses import dataclass, field, asdict
3from datetime import datetime
4from typing import Any
5
6
7@dataclass
8class Address:
9 street: str
10 city: str
11 zip_code: str
12
13
14@dataclass
15class User:
16 id: int
17 name: str
18 email: str
19 address: Address
20 tags: list[str] = field(default_factory=list)
21 created_at: datetime = field(default_factory=datetime.utcnow)
22
23 def to_json(self, **kwargs: Any) -> str:
24 def default(obj: Any) -> Any:
25 if isinstance(obj, datetime):
26 return obj.isoformat()
27 raise TypeError(f"Cannot serialize {type(obj).__name__}")
28
29 return json.dumps(asdict(self), default=default, **kwargs)
30
31 @classmethod
32 def from_json(cls, raw: str) -> "User":
33 data = json.loads(raw)
34 return cls(
35 id=data["id"],
36 name=data["name"],
37 email=data["email"],
38 address=Address(**data["address"]),
39 tags=data.get("tags", []),
40 created_at=datetime.fromisoformat(data["created_at"]),
41 )
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1asdict recursively flattens nested dataclasses into plain dicts ready for json.dumps.
- 2json.dumps accepts a default callback to teach it how to serialize types it doesn't natively understand, like datetime.
- 3Reconstruction is manual because JSON has no type info, so nested objects and datetimes must be rebuilt field by field.
Related explainers
python
from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel, ConfigDict, EmailStr from sqlalchemy.orm import Session
Building a users router in FastAPI
routing
serialization
dependency-injection
Intermediate
7 steps
rust
use std::fs::File; use std::io::{self, BufWriter}; use std::path::Path;
Serializing config to JSON in Rust
serialization
serde
file-io
Intermediate
7 steps
python
import re from django.core.exceptions import ValidationError from django.core.validators import RegexValidator
Building a deconstructible validator in Django
validation
regex
deconstructible
Intermediate
7 steps
ruby
class ArticleSerializer < ActiveModel::Serializer attributes :id, :title, :slug, :excerpt, :reading_time, :published_at, :url belongs_to :author, serializer: UserSerializer
Shaping API output with ActiveModel::Serializer in Rails
serialization
json api
computed attributes
Intermediate
9 steps
python
from dataclasses import dataclass from typing import Optional from sqlalchemy import select, func
Building a pagination helper with SQLAlchemy
pagination
dataclass
computed-properties
Intermediate
8 steps
python
from datetime import timedelta from django.contrib.sessions.models import Session from django.core.management.base import BaseCommand
A batched session-cleanup command in Django
management-command
batch-processing
database-cleanup
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/json-round-tripping-with-python-dataclasses-explained-python-aa70/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.