Imagine I have an object which is an instance of a class such as the following:
@dataclass
class Foo:
bar: int
baz: str
I'm using dataclasses
for convenience, but in the context of this question, there is no requirement that the class be a dataclass
.
Normally, if I want to unpack the attributes of such an object, I must implement __iter__
, e.g. as follows:
class Foo:
...
def __iter__(self) -> Iterator[Any]:
return iter(dataclasses.astuple(self))
bar, baz = Foo(1, "qux")
However, from the perspective of a static type checker like pyright, I've now lost any type information for bar
and baz
, which it can only infer are of type Any
. I could improve slightly by creating the iter
tuple parameter manually:
def __iter__(self) -> Iterator[Union[str, int]]:
return iter((self.bar, self.baz))
But I still don't have specific types for bar
and baz
. I can annotate bar
and baz
and then use dataclasses.astuple
directly as follows:
bar: str
baz: int
bar, baz = dataclasses.astuple(Foo(1, "qux"))
but that necessitates less readable multi-level list comprehensions such as
bars: list[int] = [
bar for bar, _ in [dataclasses.astuple(foo) for foo in [(Foo(1, "qux"))]]
]
and also ties me to dataclasses
.
Obviously, none of this is insurmountable. If I want to use a type checker, I can just not use the unpack syntax, but I would really like to if there's a clean way to do it.
An answer that is specific to dataclasses
, or better yet, attrs
, is acceptable if a general method is not currently possible.
astuple
that returns aTuple[x,y]
that you annotate correctly, and just usebar, baz = Foo.astuple()
– Trapeziumdataclasses.astuple
or other equivalents, yes, but I'm hoping for something like a dunder method trick I don't know about to make the unpack syntax work on the bare object. It could be this isn't currently possible because unpacking must use__iter__
and__iter__
must return anIterator[Union]
type when there are multiple contained types. If you can confirm that with a docs source, that would be an acceptable answer. I've been as yet unable to do so, hence the question. – Surgical