Search code examples
pythonmypy

mypy doesn't realize a dataclass's member is really what it is via `__post_init__`


I have a dataclass that contains a list[tuple[str,str]], and I'd like to be able to initialize with a dict[str,str] too. Programmatically it's this:

from dataclasses import dataclass

@dataclass
class Foobar:
    list_of_tuples: list[tuple[str, str]]

    def __post_init__(self):
        if isinstance(self.list_of_tuples, dict):
            self.list_of_tuples = list(self.list_of_tuples.items())


Foobar({"a": "b"})

but mypy isn't happy:

e.py:12: error: Argument 1 to "Foobar" has incompatible type "dict[str, str]"; expected "list[tuple[str, str]]"  [arg-type]

mypy doesn't realize I transform the dict to list[tuple] straight after initialization.

Unfortunately, there's no __pre_init__ for dataclasses. I'd like to avoid overriding __init__() as well, if possible.

Any hints?


Solution

  • If you want to initialize an object with a list of dicts, define a class method to do it explicitly.

    from dataclasses import dataclass
    
    
    @dataclass
    class Foobar:
        list_of_tuples: list[tuple[str, str]]
    
        @classmethod
        def from_dict(cls, d: dict[str, str]):
            return cls(list_of_tuples=list(d.items()))
    
    
    
    fb = Foobar.from_dict({"a": "b"})