Force type conversion in python dataclass __init__ method
The type hint of dataclass attributes is never obeyed in the sense that types are enforced or checked. Mostly static type checkers like mypy are expected to do this job, Python won't do it at runtime, as it never does.
If you want to add manual type checking code, do so in the __post_init__
method:
@dataclasses.dataclass
class Test:
value: int
def __post_init__(self):
if not isinstance(self.value, int):
raise ValueError('value not an int')
# or self.value = int(self.value)
You could use dataclasses.fields(self)
to get a tuple of Field
objects which specify the field and the type and loop over that to do this for each field automatically, without writing it for each one individually.
def __post_init__(self):
for field in dataclasses.fields(self):
value = getattr(self, field.name)
if not isinstance(value, field.type):
raise ValueError(f'Expected {field.name} to be {field.type}, '
f'got {repr(value)}')
# or setattr(self, field.name, field.type(value))
It's easy to achieve by using pydantic.validate_arguments
Just use the validate_arguments
decorator in your dataclass:
from dataclasses import dataclass
from pydantic import validate_arguments
@validate_arguments
@dataclass
class Test:
value: int
Then try your demo, the 'str type' 1 will convert from str
to int
>>> test = Test('1')
>>> type(test.value)
<class 'int'>
If you pass the truly wrong type, it will raise exception
>>> test = Test('apple')
Traceback (most recent call last):
...
pydantic.error_wrappers.ValidationError: 1 validation error for Test
value
value is not a valid integer (type=type_error.integer)