Agreed the __pre_init__ idea is no improvement. I think we're back where you started -- just use `object.__setattr__` to set the attribute in `__post_init__`. That's what the PEP says is used by the generated `__init__`, so I think it is reasonable to copy that pattern. Presumably the situation doesn't occur that frequently in real code (__post_init__ feels like a last resort hack anyway).
On Sat, Feb 17, 2018 at 5:59 PM, Ben Lewis <benlew...@gmail.com> wrote: > Why can'y you make `name` on `NamedObjectItem` a property that returns ` >> self.obj.name`? Why store a duplicate copy of the name? >> > > Agreed, it's probably a better design not to store a duplicate reference > to name. But when I tried that, the property clashed with the inherited > field. This caused the creation of the dataclass to fail as it thought that > the property was the default value for the field 'name'. Even if I set a > default for the obj field, it crashed as it tried to set the default value > for name to the read-only property. > > Although I can think of situations where properties wouldn't be sufficent > as you only want to calculate the value once per instance on creation. My > thought is that most dataclasses would still be sensible and useful even > if all mutation ability was removed from them. Taking an example directly > from the PEP: > > @dataclass > class C: > i: int > j: int = None > database: InitVar[DatabaseType] = None > > def __post_init__(self, database): > if self.j is None and database is not None: > self.j = database.lookup('j') > > Maybe I'm thinking of dataclasses wrong but this still make complete sense > and is useful even if its declared as frozen. > > My thought is that initialisation logic and immutability is orthogonal to > each other. Possibly initialisation logic like this should occur before the > instance is created so it would work for immutable types as well. > > A possible idea could be, instead of __post_init__, there is __pre_init__ > which allows altering of fields before the instance is created. It would > take a dict as first argument which contain the field values passed into > the 'constructor' and default values would also be filled out. > > @dataclass > class C: > i: int > j: int = None > database: InitVar[DatabaseType] > > @classmethod > def __pre_init__(cls, fields: Dict[str, Any], database: DatabaseType): > if fields['j'] is None and database is not None: > fields['j'] = database.lookup('j') > > I personally see two problems with this idea: > 1. This isn't as ergonomic as __post_init__ is as its modifing a > dictionary instead of its instance. > 2. To implement this, it would require a metaclass. > -- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com