Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Hasenpfote/903c3fd2ee7db16f31e18860458a6d4b to your computer and use it in GitHub Desktop.
Save Hasenpfote/903c3fd2ee7db16f31e18860458a6d4b to your computer and use it in GitHub Desktop.
How to hook properties with Python3 dataclasses.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "845a17a1-4d8f-4e19-99cd-f525f1a9d37d",
"metadata": {},
"source": [
"# How to hook properties with Python3 dataclasses.\n",
"- [Reconciling Dataclasses And Properties In Python](https://florimond.dev/en/posts/2018/10/reconciling-dataclasses-and-properties-in-python/)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "3c893311-90f4-4d9d-9cbd-bcc94bc31d7e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Python 3.8.3\n"
]
}
],
"source": [
"!python --version"
]
},
{
"cell_type": "markdown",
"id": "f62a894f-b735-4b78-968f-b961b68c365e",
"metadata": {},
"source": [
"## Use mypy to check for type errors.\n",
"[nb-mypy](https://pypi.org/project/nb-mypy/)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "346d3937-5d0d-41e6-a542-32cd5a154048",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Version 1.0.4\n"
]
}
],
"source": [
"%load_ext nb_mypy"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "1627d10a-f7e2-4908-aa38-1ac1a9018353",
"metadata": {},
"outputs": [],
"source": [
"%nb_mypy On"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "b6bb7d67-397f-453b-adfe-17a4f0ce2911",
"metadata": {},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"from typing import Optional, Union"
]
},
{
"cell_type": "markdown",
"id": "a56a8131-6e4e-4fd8-b680-5f5009440883",
"metadata": {},
"source": [
"## Want to hook properties."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "1b3e1e5a-d95d-4362-8e17-640602c94d25",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"__init__: None\n",
"getter: Barack\n",
"name: Barack\n",
"setter: Donald\n",
"getter: Donald\n",
"name Donald\n",
"setter: Joe\n",
"getter: Joe\n",
"name: Joe\n",
"{'_name': 'Joe'}\n",
"------------------------------\n",
"__init__: George\n",
"getter: George\n",
"name: George\n",
"{'_name': 'George'}\n"
]
}
],
"source": [
"class Test1:\n",
" def __init__(self, name: Optional[str] = None):\n",
" print('__init__:', name)\n",
" if name is None:\n",
" name = 'Barack'\n",
" self._name: Optional[str] = name\n",
"\n",
" @property\n",
" def name(self) -> Optional[str]:\n",
" print('getter:', self._name)\n",
" return self._name\n",
"\n",
" @name.setter\n",
" def name(self, name: str):\n",
" print('setter:', name)\n",
" self._name = name\n",
"\n",
"\n",
"t = Test1(name=None)\n",
"print('name:', t.name)\n",
"t.name = 'Donald'\n",
"print('name', t.name)\n",
"t.name = 'Joe'\n",
"print('name:', t.name)\n",
"print(vars(t))\n",
"print('-'*30)\n",
"t = Test1(name='George')\n",
"print('name:', t.name)\n",
"print(vars(t))"
]
},
{
"cell_type": "markdown",
"id": "bec14645-a582-4db9-b042-fb563fd586d1",
"metadata": {},
"source": [
"## How to do the same with dataclasses."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "3360ce92-4eff-4fc9-a33a-2d89c368bc70",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"setter: None\n",
"__post_init__\n",
"getter: None\n",
"setter: Barack\n",
"getter: Barack\n",
"name: Barack\n",
"setter: Donald\n",
"getter: Donald\n",
"name: Donald\n",
"setter: Joe\n",
"getter: Joe\n",
"name: Joe\n",
"{'_name': 'Joe'}\n",
"------------------------------\n",
"setter: George\n",
"__post_init__\n",
"getter: George\n",
"getter: George\n",
"name: George\n",
"{'_name': 'George'}\n"
]
}
],
"source": [
"@dataclass\n",
"class Test2:\n",
" name: Optional[Union[str, property]] = None\n",
"\n",
" def __post_init__(self):\n",
" print('__post_init__')\n",
" if self.name is None:\n",
" self.name = 'Barack'\n",
"\n",
" def _get_name(self) -> Optional[str]:\n",
" print('getter:', self._name)\n",
" return self._name\n",
"\n",
" def _set_name(self, name: str):\n",
" print('setter:', name)\n",
" self._name = name\n",
"\n",
"# Note that this must be a module-level call.\n",
"Test2.name = property(Test2._get_name, Test2._set_name)\n",
"\n",
"t = Test2(name=None)\n",
"print('name:', t.name)\n",
"t.name = 'Donald'\n",
"print('name:', t.name)\n",
"t.name = 'Joe'\n",
"print('name:', t.name)\n",
"print(vars(t))\n",
"print('-'*30)\n",
"t = Test2(name='George')\n",
"print('name:', t.name)\n",
"print(vars(t))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.8.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment