Type Hint For An Instance Of A Non Specific Dataclass
Solution 1:
Despite its name, dataclasses.dataclass
doesn't expose a class interface. It just allows you to declare a custom class in a convenient way that makes it obvious that it is going to be used as a data container. So, in theory, there is little opportunity to write something that only works on dataclasses, because dataclasses really are just ordinary classes.
In practice, there a couple of reasons why you would want to declare dataclass-only functions anyway, and I see two ways to go about it.
The right way, using a static type checker and writing a Protocol
from dataclasses import dataclassfrom typing importDictfrom typing_extensions import Protocol
classIsDataclass(Protocol):
# as already noted in comments, checking for this attribute is currently# the most reliable way to ascertain that something is a dataclass
__dataclass_fields__: Dictdefdataclass_only(x: IsDataclass):
... # do something that only makes sense with a dataclass@dataclassclassA:
pass
dataclass_only(A()) # a static type check should show that this line is fine
This approach is also what you alluded to in your question, but it has three downsides:
- You need a third party library such as
mypy
to do the static type checking for you - If you are on python 3.7 or earlier, you need to manually install
typing_extensions
as well, sinceProtocol
is not part of the coretyping
module in them - Last but not least, using protocols for dataclasses in this way doesn't work right now
Something slightly more EAFP-inspired that actually works
from dataclasses import is_dataclassdef dataclass_only(x):
"""Do something that only makes sense with a dataclass.
Raises:
ValueError if something that is not a dataclass is passed.
... more documentation ...
"""ifnot is_dataclass(x):
raise ValueError(f"'{x.__class__.__name__}' is not a dataclass!")
...
In this approach, the behavior is still very clear to a maintainer or user of this code thanks to the documentation. But the downside is that you don't get a static analysis of your code (including type hints by your IDE), not now and not ever.
Solution 2:
There is a helper function called is_dataclass
that can be used, its exported from dataclasses
.
Basically what it does is this:
defis_dataclass(obj):
"""Returns True if obj is a dataclass or an instance of a
dataclass."""
cls = obj ifisinstance(obj, type) elsetype(obj)
returnhasattr(cls, _FIELDS)
It gets the type of the instance using type, or if the object extends type, the object itself.
It then checks if the variable _FIELDS, which equals __dataclass_fields__
, exists on this object. This is basically equivalent to the other answers here.
To "type" dataclass i would do something like this:
classDataclassProtocol(Protocol):
__dataclass_fields__: Dict
__dataclass_params__: Dict
__post_init__: Optional[Callable]
Post a Comment for "Type Hint For An Instance Of A Non Specific Dataclass"