title: Validating detailed types in python dataclasses
body: <p>Python 3.7 was released a while ago, and I wanted to test some of the fancy new <code>dataclass</code>+typing features. Getting hints to work right is easy enough, with both native types and those from the <code>typing</code> module:</p>
  <pre><code>&gt;&gt;&gt; import dataclasses
  &gt;&gt;&gt; import typing as ty
  &gt;&gt;&gt; 
  ... @dataclasses.dataclass
  ... class Structure:
  ...     a_str: str
  ...     a_str_list: ty.List[str]
  ...
  &gt;&gt;&gt; my_struct = Structure(a_str='test', a_str_list=['t', 'e', 's', 't'])
  &gt;&gt;&gt; my_struct.a_str_list[0].  # IDE suggests all the string methods :)
  </code></pre>
  <p>But one other thing that I wanted to try was forcing the type hints as conditions during runtime, i.e. it should not be possible for a <code>dataclass</code> with incorrect types to exist. It can be implemented nicely with <a href="https://www.python.org/dev/peps/pep-0557/#post-init-processing" rel="noreferrer"><code>__post_init__</code></a>:</p>
  <pre><code>&gt;&gt;&gt; @dataclasses.dataclass
  ... class Structure:
  ...     a_str: str
  ...     a_str_list: ty.List[str]
  ...     
  ...     def validate(self):
  ...         ret = True
  ...         for field_name, field_def in self.__dataclass_fields__.items():
  ...             actual_type = type(getattr(self, field_name))
  ...             if actual_type != field_def.type:
  ...                 print(f&quot;\t{field_name}: '{actual_type}' instead of '{field_def.type}'&quot;)
  ...                 ret = False
  ...         return ret
  ...     
  ...     def __post_init__(self):
  ...         if not self.validate():
  ...             raise ValueError('Wrong types')
  </code></pre>
  <p>This kind of <code>validate</code> function works for native types and custom classes, but not those specified by the <code>typing</code> module:</p>
  <pre><code>&gt;&gt;&gt; my_struct = Structure(a_str='test', a_str_list=['t', 'e', 's', 't'])
  Traceback (most recent call last):
    a_str_list: '&lt;class 'list'&gt;' instead of 'typing.List[str]'
    ValueError: Wrong types
  </code></pre>
  <p>Is there a better approach to validate an untyped list with a <code>typing</code>-typed one? Preferably one that doesn't include checking the types of all elements in any <code>list</code>, <code>dict</code>, <code>tuple</code>, or <code>set</code> that is a <code>dataclass</code>' attribute.</p>
  <hr />
  <p>Revisiting this question after a couple of years, I've now moved to use <a href="https://pydantic-docs.helpmanual.io/" rel="noreferrer"><code>pydantic</code></a> in cases where I want to validate classes that I'd normally just define a dataclass for. I'll leave my mark with the currently accepted answer though, since it correctly answers the original question and has outstanding educational value.</p>