5

I am not sure what I am doing wrong. How to prevent the Test class to accept & throw error, when input of different types are passed. I am using Python 3.9.2

from dataclasses import dataclass, fields


@dataclass
class Test:
    a: str = 'a'
    b: int = 1


t = Test(2, 'b')

print(fields(t))
print(type(t.a))
print(type(t.b))

# output
# (venv) D:\Playground>python dataClassesTest.py
# (Field(name='a',type=<class 'str'>,default='a',default_factory=<dataclasses._MISSING_TYPE object at 0x00000232952D5880>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD), Field(name='b',type=<class 'int'>,default=1,default_factory=<dataclasses._MISSING_TYPE object at 0x00000232952D5880>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD))
# <class 'int'>
# <class 'str'>
Dinesh Ravi
  • 1,209
  • 1
  • 17
  • 35
  • 2
    This is not the `dataclass`'s job to raise exception when a type doesn't match. I think there are some static type checkers out there that will raise exception. – S.B Sep 28 '21 at 17:50
  • 3
    pydantic is your best friend for this :-) – rv.kvetch Sep 29 '21 at 23:23
  • 1
    you can do it with dataclasses - try googling run time checking with dataclasses - but it's a bit kludgy to say the least IMHO. ...I'd 2nd if you want run time checking try pydantic instead – Richard Oct 03 '21 at 03:32

1 Answers1

4

This can be solved by adding a __post_init__ method to your dataclass where you can check the types

(Based on this solution, with some corrections)

def __post_init__(self):
    for f in fields(type(self)):
        if not isinstance(getattr(self, f.name), f.type):
            current_type = type(getattr(self, f.name))
            raise TypeError(f"The field `{f.name}` was assigned by `{current_type}` instead of `{f.type}`")

Note that this code doesn't work when importing

from __future__ import annotations

Because then the type field in dataclasses.Field becomes a string

user107511
  • 772
  • 3
  • 23