Thanks all for the replies!
The downside I see to namedtuple
is that you need to be comfortable buying into the object being an actual tuple. I often don’t want many of the features that tuples provide:
>>> from typing import NamedTuple
>>> class Point(NamedTuple):
... x: float
... y: float
...
>>> p = Point(1, 2)
>>> q = Point(3, 4)
>>> p + q
(1, 2, 3, 4)
>>> p * 2
(1, 2, 1, 2)
>>> len(p)
3
As others have noted, using astuple
isn’t quite right and I didn’t use it in my linked example code and probably should have noted its downsides in my initial post.
As @peterc noted, the astuple
function deeply copies (which is unnecessary for this use case). But even weirder it deeply converts all dataclasses to tuples, as @DavidCEllis noted.
>>> from dataclasses import astuple, dataclass
>>>
>>> @dataclass
... class A:
... n: float
... m: float
...
>>> @dataclass
... class B:
... a: A
... x: float
... y: float
... def __iter__(self):
... return iter(astuple(self))
...
>>> b = B(a=A(1, 2), x=3, y=4)
>>> list(b)
[(1, 2), 3, 4]
The way to implement __iter__
correctly might look like this:
def __iter__(self):
for field in dataclasses.fields(cls):
yield getattr(self, field.name)
If there was a less verbose way to correctly implement this, I wouldn’t be so tempted to propose adding iter=True
to dataclasses.dataclass
.