I have to imagine that the type checkers would factor in anything that occurs in __post_init__ when evaluating whether the class conforms to the type hints, but it still feels like this python static typing stuff is drifting in the wrong direction.
I have to imagine that the type checkers would factor in anything that occurs in __post_init__ when evaluating whether the class conforms to the type hints, but it still feels like this python static typing stuff is drifting in the wrong direction.
Arguments accepted in __init__() are not necessarily tied to the so-called "shape of the type" at runtime. Fields with init=False, and the presence of ClassVar and InitVar is just two examples.
In terms of types of arguments passed to __init__(), they totally can be incompatible with the runtime type of the given field. There's nothing wrong with that. On the contrary, that is a useful feature. The obvious example is factories for field defaults. E.g. you can't store a list instance as a default value, it would be reused across your type's instances. Instead, you use default_factory=list. But when you do, what type does the respective argument to __init__ accept? Well, it's Union[YourType, MISSING] because you can omit it and it will initialize your type for you.
Type conversion is another common example. Your __init__ might accept timestamps as strings but always convert them to datetimes. Maybe you accept Unicode strings but internally store as bytes or vice versa? Maybe you support an external API so you have to accept a bunch of arguments that you later convert to a saner internal state? There are numerous use cases.
Summing up, don't confuse the signature of __init__ with the type shape.
@dataclass
class DataObj:
some_date: datetime
def __init__(self, **kw):
kw['some_date'] = dateutil.parser.parse(kw['some_date'])
super().__init__(**kw) dataclass.__init__(self, **kw)
Like in the olden days before super(). @dataclass
class BaseDataObj:
some_date: datetime
class DataObj(BaseDataObj):
def __init__(self, **kw):
kw['some_date'] = dateutil.parser.parse(kw['some_date'])
super().__init__(**kw)