4 ms·
This __post_init__ thing is shit IMO. Why does it make sense for the language feature to allow you to completely disregard the type hint and fix it later? I h
by david-cako 9y ago
This __post_init__ thing is shit IMO. Why does it make sense for the language feature to allow you to completely disregard the type hint and fix it later?
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.
- cpburns2009 9y agoI don't like `__post_init__` either. Wouldn't it make more sense to just override `__init__` similar to: @dataclass class DataObj: some_date: datetime def __init__(self, **kw): kw['some_date'] = dateutil.parser.parse(kw['some_date']) super().__init__(**kw)
- dragonwriter 9y agoTo allow you to override init that way, @dataclass would have to create an additional superclass with the generated init method, rather than generating the init method in the class intended for use, which seems to have more overhead.
- cpburns2009 9y agoYeah, good point. I didn't think that through very much.
- ptx 9y agoYou could attach the __init__ method to dataclass (as if it were a class) and call it like this, couldn't you? dataclass.__init__(self, **kw) Like in the olden days before super().
- dragonwriter 9y agoFrom the description, the dataclass decorator generates an __init__ method for the decorated class, which seems different than using a common generic __init__ method for all classes with the decorator.
- bobbyi_settv 9y agoIf you want to do it that way, I imagine you could use regular subclassing @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)
- ambivalence 9y agoJudging from your confrontational tone I will probably regret commenting but here goes. 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.
- weberc2 9y agoI disagree. __init__() should do little more than assign attributes to parameter values, with the exception of handling `None` default parameters, and this exception only exists because Python's default parameters don't behave intuitively.
- kstrauser 9y agoThey're not intuitive, but they are consistent. It would be very surprising if `a=[]` behaved differently in a function definition (which isn't just syntax, but an executable Python statement) than elsewhere.
- weberc2 9y agoI disagree. ‘a=[]’ is inconsistent in function definitions today because the rhs is evaluated at interpreter load time but the assignment is evaluated at call time. The intuitive thing is would be to evaluate the whole expression at once (at call time) just like everywhere else.