Reputation: 691
I have a dataclass:
import dataclasses
@dataclasses.dataclass
class Foo:
first: dict[str, int]
How can I determine that the generic type dict
is the type expected with a str
to int
mapping? I want to be able to do something like:
for field in dataclasses.fields(Foo):
if generic_type_of_field == dict:
<<do something specific to this field needing to be a dict>>
elif generic_type_of_field == list:
<<do something specific to this field needing to be a list>>
I have tried using dataclasses.fields(Foo)
to get the fields, then taking field.type
. This just gives me dict[str, int]
which is a <class 'types.GenericAlias'>
type. Is there something more I can do here?
I can get the paramaterizations of the dict
generic via get_args(field.type)
which gives me (<class 'str'>, <class 'int'>)
(which I do need) but I don't have run out of knowledge on even searching on the topic now so I am asking here.
Upvotes: 1
Views: 205
Reputation: 18568
If you want to be able to tell the original generic type of a specified generic type, you can use typing.get_origin
.
The problem is that it will return None
, if you pass it a non-specified generic type. If you want to account for that, the simplest solution I can think of something along these lines:
import dataclasses
from typing import get_origin
@dataclasses.dataclass
class Foo:
first: dict[str, int]
second: dict
third: list[float]
def generic_base(t: type) -> type:
origin = get_origin(t)
if origin is not None:
return origin
return t
if __name__ == '__main__':
for field in dataclasses.fields(Foo):
if generic_base(field.type) is dict:
print(field.name, "is a dict")
elif generic_base(field.type) is list:
print(field.name, "is a list")
The output:
first is a dict
second is a dict
third is a list
Upvotes: 1