Last active
June 20, 2023 15:58
-
-
Save malcolmgreaves/b42491da7c051c6f635275107473858f to your computer and use it in GitHub Desktop.
Adds syntactic support to destructing an @DataClass into field-values the same way a NamedTuple (or tuple) is.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC | |
from typing import Any, Iterable, Tuple | |
from dataclasses import dataclass | |
from functools import partial | |
@dataclass | |
class TupleDestructureSyntax(ABC): | |
"""Allows any @dataclass class to be decomposed into its fields & values as if it were a tuple. | |
For example, if a `@dataclass` `X` has three fields: | |
@dataclass class X: | |
a: int | |
b: str | |
c: float | |
Then, given an instance `x`, it can be destructured into its components using the same syntax | |
that applies to tuples (and thuss `NamedTuple`-extending classes) as: | |
x: X = ... | |
a, b, c = x | |
""" | |
def __iter__(self) -> Iterable[Tuple[Any, ...]]: | |
return iter(tuple(map(partial(getattr, self), self.__dataclass_fields__.keys()))) | |
# runnable example produces this output: | |
# >>> | |
# z=Z(name='bob', money=3.51, age=42) | |
# Z=<class '__main__.Z'> | |
# name='bob' | |
# money=3.51 | |
# age=42 | |
# the 2nd example class shows that inheritence still works: | |
# >>> | |
# a=A(name='jane', money=9999., age=3, location='earth') | |
# name='jane' | |
# money=9999.0 | |
# age=3 | |
# location='earth' | |
@dataclass(frozen=True) | |
class Z(TupleDestructureSyntax): | |
name: str | |
money: float | |
age: int | |
z = Z("bob", 3.51, 42) | |
print(f"{z=}") | |
print(f"{Z=}") | |
name, money, age = z | |
print(f"{name=}") | |
print(f"{money=}") | |
print(f"{age=}") | |
@dataclass(frozen=True) | |
class A(Z): | |
location: str | |
a = A('jane', 9999., 3, "earth") | |
print(f"{a=}") | |
name, money, age, location = a | |
print(f"{name=}") | |
print(f"{money=}") | |
print(f"{age=}") | |
print(f"{location=}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Running this example produces: