On 11/27/2017 6:01 AM, Sebastian Rittau wrote: > On 25.11.2017 22:06, Eric V. Smith wrote: >> The major changes from the previous version are: >> >> - Add InitVar to specify initialize-only fields. > > This is the only feature that does not sit right with me. It looks very > obscure and "hacky". From what I understand, we are supposed to use the > field syntax to define constructor arguments. I'd argue that the name > "initialize-only fields" is a misnomer, which only hides the fact that > this has nothing to do with fields at all. Couldn't dataclassses just > pass *args and **kwargs to __post_init__()? Type checkers need to be > special-cases for InitVar anyway, couldn't they instead be special cased > to look at __post_init__ argument types? First off, I expect this feature to be used extremely rarely. I'm tempted to remove it, since it's infrequently needed and it could be added later. And as the PEP points out, you can get most of the way with an alternate classmethod constructor. I had something like your suggestion half coded up, except I inspected the args to __post_init__() and added them to __init__, avoiding the API-unfriendly *args and **kwargs. So in: @dataclass class C: x: int y: int def __post_init__(self, database: DatabaseType): pass Then the __init__ signature became: def __init__(self, x:int, y:int, database:DatabaseType): In the end, that seems like a lot of magic (but what about this isn't?), it required the inspect module to be imported, and I thought it made more sense for all of the init params to be near each other: @dataclass class C: x: int y: int database: InitVar[DatabaseType] def __post_init__(self, database): pass No matter what we do here, static type checkers are going to have to be aware of either the InitVars or the hoisting of params from __post_init__ to __init__. One other thing about InitVar: it lets you control where the init-only parameter goes in the __init__ call. This is especially important with default values: @dataclass class C: x: int database: InitVar[DatabaseType] y: int = 0 def __post_init__(self, database): pass In this case, if I were hoisting params from __post_init__ to __init__, the __init__ call would be: def __init__(self, x, y=0, database) Which is an error. I guess you could say the init-only parameters would go first in the __init__ definition, but then you have the same problem if any of them have default values. Eric.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4