What does attrs' solution for this problem look like?

On Fri, Jan 26, 2018 at 11:11 AM, George Leslie-Waksman <waks...@gmail.com>
wrote:

> Even if we could inherit the setting, I would think that we would still
> want to require the code be explicit. It seems worse to implicitly require
> keyword only arguments for a class without giving any indication in the
> code.
>
> As it stands, the current implementation does not allow a later subclass
> to be declared without `keyword_only=True` so we could handle this case by
> adding a note to the `TypeError` message about considering the keyword_only
> flag.
>
> How do I got about putting together a proposal to get this into 3.8?
>
> --George
>
>
> On Thu, Jan 25, 2018 at 5:12 AM Eric V. Smith <e...@trueblade.com> wrote:
>
>> I'm not completely opposed to this feature. But there are some cases to
>> consider. Here's the first one that occurs to me: note that due to the
>> way dataclasses work, it would need to be used everywhere down an
>> inheritance hierarchy. That is, if an intermediate base class required
>> it, all class derived from that intermediate base would need to specify
>> it, too. That's because each class just makes decisions based on its
>> fields and its base classes' fields, and not on any flags attached to
>> the base class. As it's currently implemented, a class doesn't remember
>> any of the decorator's arguments, so there's no way to look for this
>> information, anyway.
>>
>> I think there are enough issues here that it's not going to make it in
>> to 3.7. It would require getting a firm proposal together, selling the
>> idea on python-dev, and completing the implementation before Monday. But
>> if you want to try, I'd participate in the discussion.
>>
>> Taking Ivan's suggestion one step further, a way to do this currently is
>> to pass init=False and then write another decorator that adds the
>> kw-only __init__. So the usage would be:
>>
>> @dataclass
>>      class Foo:
>>          some_default: dict = field(default_factory=dict)
>>
>> @kw_only_init
>> @dataclass(init=False)
>> class Bar(Foo):
>>      other_field: int
>>
>> kw_only_init(cls) would look at fields(cls) and construct the __init__.
>> It would be a hassle to re-implement dataclasses's _init_fn function,
>> but it could be made to work (in reality, of course, you'd just copy it
>> and hack it up to do what you want). You'd also need to use some private
>> knowledge of InitVars if you wanted to support them (the stock
>> fields(cls) doesn't return them).
>>
>> For 3.8 we can consider changing dataclasses's APIs if we want to add
>> this.
>>
>> Eric.
>>
>> On 1/25/2018 1:38 AM, George Leslie-Waksman wrote:
>> > It may be possible but it makes for pretty leaky abstractions and it's
>> > unclear what that custom __init__ should look like. How am I supposed to
>> > know what the replacement for default_factory is?
>> >
>> > Moreover, suppose I want one base class with an optional argument and a
>> > half dozen subclasses each with their own required argument. At that
>> > point, I have to write the same __init__ function a half dozen times.
>> >
>> > It feels rather burdensome for the user when an additional flag (say
>> > "kw_only=True") and a modification to:
>> > https://github.com/python/cpython/blob/master/Lib/dataclasses.py#L294
>>  that
>> > inserted `['*']` after `[self_name]` if the flag is specified could
>> > ameliorate this entire issue.
>> >
>> > On Wed, Jan 24, 2018 at 3:22 PM Ivan Levkivskyi <levkivs...@gmail.com
>> > <mailto:levkivs...@gmail.com>> wrote:
>> >
>> >     It is possible to pass init=False to the decorator on the subclass
>> >     (and supply your own custom __init__, if necessary):
>> >
>> >     @dataclass
>> >     class Foo:
>> >          some_default: dict = field(default_factory=dict)
>> >
>> >     @dataclass(init=False) # This works
>> >     class Bar(Foo):
>> >          other_field: int
>> >
>> >     --
>> >     Ivan
>> >
>> >
>> >
>> >     On 23 January 2018 at 03:33, George Leslie-Waksman
>> >     <waks...@gmail.com <mailto:waks...@gmail.com>> wrote:
>> >
>> >         The proposed implementation of dataclasses prevents defining
>> >         fields with defaults before fields without defaults. This can
>> >         create limitations on logical grouping of fields and on
>> inheritance.
>> >
>> >         Take, for example, the case:
>> >
>> >         @dataclass
>> >         class Foo:
>> >              some_default: dict = field(default_factory=dict)
>> >
>> >         @dataclass
>> >         class Bar(Foo):
>> >              other_field: int
>> >
>> >         this results in the error:
>> >
>> >                5 @dataclass
>> >         ----> 6 class Bar(Foo):
>> >                7     other_field: int
>> >                8
>> >
>> >         ~/.pyenv/versions/3.6.2/envs/clover_pipeline/lib/python3.6/
>> site-packages/dataclasses.py
>> >         in dataclass(_cls, init, repr, eq, order, hash, frozen)
>> >              751
>> >              752     # We're called as @dataclass, with a class.
>> >         --> 753     return wrap(_cls)
>> >              754
>> >              755
>> >
>> >         ~/.pyenv/versions/3.6.2/envs/clover_pipeline/lib/python3.6/
>> site-packages/dataclasses.py
>> >         in wrap(cls)
>> >              743
>> >              744     def wrap(cls):
>> >         --> 745         return _process_class(cls, repr, eq, order,
>> >         hash, init, frozen)
>> >              746
>> >              747     # See if we're being called as @dataclass or
>> >         @dataclass().
>> >
>> >         ~/.pyenv/versions/3.6.2/envs/clover_pipeline/lib/python3.6/
>> site-packages/dataclasses.py
>> >         in _process_class(cls, repr, eq, order, hash, init, frozen)
>> >              675                                 #  in __init__.  Use
>> >         "self" if possible.
>> >              676                                 '__dataclass_self__' if
>> >         'self' in fields
>> >         --> 677                                     else 'self',
>> >              678                                 ))
>> >              679     if repr:
>> >
>> >         ~/.pyenv/versions/3.6.2/envs/clover_pipeline/lib/python3.6/
>> site-packages/dataclasses.py
>> >         in _init_fn(fields, frozen, has_post_init, self_name)
>> >              422                 seen_default = True
>> >              423             elif seen_default:
>> >         --> 424                 raise TypeError(f'non-default argument
>> >         {f.name <http://f.name>!r} '
>> >              425                                 'follows default
>> argument')
>> >              426
>> >
>> >         TypeError: non-default argument 'other_field' follows default
>> >         argument
>> >
>> >         I understand that this is a limitation of positional arguments
>> >         because the effective __init__ signature is:
>> >
>> >         def __init__(self, some_default: dict = <something>,
>> >         other_field: int):
>> >
>> >         However, keyword only arguments allow an entirely reasonable
>> >         solution to this problem:
>> >
>> >         def __init__(self, *, some_default: dict = <something>,
>> >         other_field: int):
>> >
>> >         And have the added benefit of making the fields in the __init__
>> >         call entirely explicit.
>> >
>> >         So, I propose the addition of a keyword_only flag to the
>> >         @dataclass decorator that renders the __init__ method using
>> >         keyword only arguments:
>> >
>> >         @dataclass(keyword_only=True)
>> >         class Bar(Foo):
>> >              other_field: int
>> >
>> >         --George Leslie-Waksman
>> >
>> >         _______________________________________________
>> >         Python-ideas mailing list
>> >         Python-ideas@python.org <mailto:Python-ideas@python.org>
>> >         https://mail.python.org/mailman/listinfo/python-ideas
>> >         Code of Conduct: http://python.org/psf/codeofconduct/
>> >
>> >
>> >
>> >
>> > _______________________________________________
>> > Python-ideas mailing list
>> > Python-ideas@python.org
>> > https://mail.python.org/mailman/listinfo/python-ideas
>> > Code of Conduct: http://python.org/psf/codeofconduct/
>> >
>>
>>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>


-- 
--Guido van Rossum (python.org/~guido)
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to