What type hint will be exposed for the __init__ parameter? Clearly, it's not a `str` type in your example; you're passing it an `int` value in your example. Presumably to overcome this, you'd need yet another `field` function parameter to provide the type hint for the `__init__` param?
On Wed, 2022-06-22 at 20:43 +0000, Dexter Hill wrote: > The idea is to have a `default_factory` like argument (either in the > `field` function, or a new function entirely) that takes a function > as an argument, and that function, with the value provided by > `__init__`, is called and the return value is used as the value for > the respective field. For example: > ```py > @dataclass > class Foo: > x: str = field(init_fn=chr) > > f = Foo(65) > f.x # "A" > ``` > The `chr` function is called, given the value `65` and `x` is set to > its return value of `"A"`. I understand that there is both `__init__` > and `__post_init__` which can be used for this purpose, but sometimes > it isn't ideal to override them. If you overrided `__init__`, and > were using `__post_init__`, you would need to manually call it, and > in my case, `__post_init__` is implemented on a base class, which all > other classes inherit, and so overloading it would require re- > implementing the logic from it (and that's ignoring the fact that you > also need to type the field with `InitVar` to even have it passed to > `__post_init__` in the first place). > > I've created a proof of concept, shown below: > ```py > def initfn(fn, default=None): > class Inner: > def __set_name__(_, owner_cls, owner_name): > old_setattr = getattr(owner_cls, "__setattr__") > > def __setattr__(self, attr_name, value): > > if attr_name == owner_name: > # Bypass `__setattr__` > self.__dict__[attr_name] = fac(value) > > else: > old_setattr(self, attr_name, value) > > setattr(owner_cls, "__setattr__", __setattr__) > > def fac(value): > if isinstance(value, Inner): > return default > > return fn(value) > > return field(default=Inner()) > ``` > It makes use of the fact that providing `default` as an argument to > `field` means it checks the value for a `__set_name__` function, and > calls it with the class and field name as arguments. Overriding > `__setattr__` is just used to catch when a value is being assigned to > a field, and if that field's name matches the name given to > `__set_name__`, it calls the function on the value, at sets the field > to that instead. > It can be used like so: > ```py > @dataclass > class Foo: > x: str = initfn(fn=chr, default="Z") > > f = Foo(65) > f2 = Foo() > > f.x # "A" > f2.x # "Z" > ``` > It adds a little overhead, especially with having to override > `__setattr__` however, I believe it would have very little overhead > if directly implemented in the dataclass library. > > Even in the case of being able to override one of the init functions, > I still think it would be nice to have as a quality of life feature > as I feel calling a function is too simple to want to override the > functions, if that makes sense. > > Thanks. > Dexter > _______________________________________________ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-le...@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at > https://mail.python.org/archives/list/python-ideas@python.org/message/4SM5EVP6MMGGHQMZSJXBML74PWWDHEWV/ > Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/N2JQWHBBKVDK3VJAFVUY5YCT5MZOTPPN/ Code of Conduct: http://python.org/psf/codeofconduct/