Skip to content

Instantly share code, notes, and snippets.

@MtkN1
Created July 28, 2024 16:00
Show Gist options
  • Save MtkN1/cbc42fb29565a854b6683ac3981ec576 to your computer and use it in GitHub Desktop.
Save MtkN1/cbc42fb29565a854b6683ac3981ec576 to your computer and use it in GitHub Desktop.
pydantic vs. cattrs performance
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"import urllib.request\n",
"from dataclasses import dataclass\n",
"from typing import TypeAlias, TypedDict\n",
"\n",
"import orjson\n",
"import pydantic_core\n",
"from attrs import define\n",
"from cattrs import structure\n",
"from pydantic import BaseModel, TypeAdapter\n",
"\n",
"url = \"https://jsonplaceholder.typicode.com/posts\"\n",
"\n",
"with urllib.request.urlopen(url) as response:\n",
" json_content = response.read()\n",
"\n",
"\n",
"class TypedDictPost(TypedDict):\n",
" userId: int\n",
" id: int\n",
" title: str\n",
" body: str\n",
"\n",
"\n",
"TypedDictPosts: TypeAlias = list[TypedDictPost]\n",
"\n",
"\n",
"@dataclass\n",
"class DataclassPost:\n",
" userId: int\n",
" id: int\n",
" title: str\n",
" body: str\n",
"\n",
"\n",
"DataclassPosts: TypeAlias = list[DataclassPost]\n",
"\n",
"\n",
"@define\n",
"class AttrsPost:\n",
" userId: int\n",
" id: int\n",
" title: str\n",
" body: str\n",
"\n",
"\n",
"AttrsPosts: TypeAlias = list[AttrsPost]\n",
"\n",
"\n",
"class PydanticPost(BaseModel):\n",
" userId: int\n",
" id: int\n",
" title: str\n",
" body: str\n",
"\n",
"\n",
"PydanticPosts = TypeAdapter(list[PydanticPost])"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"113 μs ± 12.9 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
"136 μs ± 18.7 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
"34.4 μs ± 1.73 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n"
]
}
],
"source": [
"# Parse Any JSON\n",
"%timeit json.loads(json_content)\n",
"%timeit pydantic_core.from_json(json_content)\n",
"%timeit orjson.loads(json_content)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"91.3 μs ± 15.8 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
"112 μs ± 4.29 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
"132 μs ± 23.2 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n"
]
}
],
"source": [
"# Parse JSON with cattrs \n",
"%timeit structure(orjson.loads(json_content), TypedDictPosts)\n",
"%timeit structure(orjson.loads(json_content), DataclassPosts)\n",
"%timeit structure(orjson.loads(json_content), AttrsPosts)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"154 μs ± 5.66 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n",
"140 μs ± 20.1 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n"
]
}
],
"source": [
"# Parse JSON with pydantic\n",
"%timeit PydanticPosts.validate_json(json_content)\n",
"%timeit PydanticPosts.validate_python(orjson.loads(json_content))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment