Issue 33539: Remove init flag from @dataclass? (original) (raw)

Issue33539

Created on 2018-05-16 14:53 by barry, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (14)
msg316812 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2018-05-16 14:53
In reading over the new dataclasses documentation, I'm unsure what the `init` flag is used for, given that: * If you already have a __init__(), then dataclasses won't add one * If you don't have a __init__(), why wouldn't you want dataclasses to add one? Without that, how do your attributes get initialized? If there is a valid use case for `init`, I'm happy to add it to the documentation. If there isn't, can we call YAGNI and remove the flag? I'm mildly of the same opinion with `repr` but I can see some value in wanting to defer to object.__repr__(). OTOH, it should be pretty easy to just write: @dataclass class Foo: def __repr__(self): return super.__repr__()
msg316816 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2018-05-16 15:10
Make that `return super().__init__()` of course. I can haz (editable) GitHub issues!
msg316826 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-16 16:02
The behavior used to be that we'd raise an error if you tried to overwrite a dunder method. Then we decided that the existence of a dunder method meant you didn't want it overwritten, so now we don't need to explicitly set a flag to False in that case. However, we did not go back and see which of the flags still make sense. I can't think of a reason why anyone would use the `init` parameter to @dataclass. It's a little late in the 3.7 release cycle to remove it, so maybe we can decide to deprecate it in 3.8? Although if there's clearly no reason for it to exist, I could be talked in to removing it. We should probably go through every flag and decide about it individually.
msg316828 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2018-05-16 16:07
On May 16, 2018, at 12:02, Eric V. Smith <report@bugs.python.org> wrote: > > It's a little late in the 3.7 release cycle to remove it, so maybe we can decide to deprecate it in 3.8? Although if there's clearly no reason for it to exist, I could be talked in to removing it. I think we should get an exemption and just remove it. There’s no reason to incur such tech-debt right off the bat. > We should probably go through every flag and decide about it individually. +1
msg316829 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2018-05-16 16:09
+ned.deily for the 3.7 exemption.
msg316830 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2018-05-16 16:16
If we agree that we don't need it, the time to do it is now, before 3.7.0 releases.
msg316852 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-16 19:21
Larry points out that one potential use case is a base class that defines some awesome __init__ that you want to use. Without init=False, there’s no good way to use it.
msg316855 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2018-05-16 19:56
Really? Why doesn't this work in the derived dataclass? def __init__(self, *args, **kws): super().__init__(*args, **kws)
msg316859 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-16 20:09
I think the concern is: from dataclasses import * class B: def __init__(self, a, b, c): # do something with a, b, c, and maybe use fields(self) to figure out we have a "i" field self.i = a + b + c @dataclass(init=False) class C(B) i: int c = C(1, 2, 3) It doesn't seem particularly likely, but do we want to prevent it?
msg316861 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2018-05-16 20:35
On May 16, 2018, at 16:09, Eric V. Smith <report@bugs.python.org> wrote: > > I think the concern is: > > from dataclasses import * > > class B: > def __init__(self, a, b, c): > # do something with a, b, c, and maybe use fields(self) to figure out we have a "i" field > self.i = a + b + c > > @dataclass(init=False) > class C(B) > i: int > > c = C(1, 2, 3) > > It doesn't seem particularly likely, but do we want to prevent it? What are the intended semantics of this? I know what happens; c.i == 6 So, if I remove `init=False` and add an explicit __init__(), the same thing still happens. Is that good enough? from dataclasses import * class B: def __init__(self, a, b, c): # do something with a, b, c, and maybe use fields(self) to figure out we # have a "i" field self.i = a + b + c @dataclass class C(B): i: int def __init__(self, a, b, c): super().__init__(a, b, c) c = C(1, 2, 3) (Or maybe it’s the “use fields(self)” bit that you’re pointing out?)
msg316865 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-16 20:48
The concern is that you've created an awesome base class, and you've written 500 dataclasses that are derived from it, but you want to use the base class's __init__ for all 500. Do you really want to add a __init__ to each of the 500 classes? We're trying to reduce boilerplate! Again, I'm not saying it's likely. The comment about fields(self) is meant to say that they could be inspecting the derived class to figure out which field to set. Something like: class B: def __init__(self, a, b, c): first_field = next(iter(fields(self))) setattr(self, first_field.name, a+b+c) mydataclass = dataclass(init=False) @mydataclass class C(B): i: int @mydataclass class D(B): j: int print(C(1, 2, 3)) print(D(4, 5, 6)) produces: C(i=6) D(j=15) That is, the base class could legitimately being doing something with the derived class fields, and you might want to move all of the logic in to a base class.
msg316870 - (view) Author: Barry A. Warsaw (barry) * (Python committer) Date: 2018-05-16 21:12
On May 16, 2018, at 16:48, Eric V. Smith <report@bugs.python.org> wrote: > Do you really want to add a __init__ to each of the 500 classes? Well, of course *I* do, but I’m weird like that. > That is, the base class could legitimately being doing something with the derived class fields, and you might want to move all of the logic in to a base class. Yeah, I can see the points. I think if these are use cases we want to support, maybe we should describe them in the documentation as justifications for the keyword arguments.
msg316878 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-05-17 01:05
I find it a satisfying outcome that we decided *not* to remove this in the last week before rc1. While it's true that dataclasses are a new feature in 3.7.0, considerable effort went into stabilizing the betas. Let's close this issue.
msg316879 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-17 01:12
Okay. I'm sure Ned is relieved!
History
Date User Action Args
2022-04-11 14:59:00 admin set github: 77720
2018-05-17 01:12:31 eric.smith set status: open -> closedpriority: release blocker -> type: behaviormessages: + resolution: wont fixstage: resolved
2018-05-17 01:05:24 gvanrossum set messages: +
2018-05-16 21:12:55 barry set messages: +
2018-05-16 20:48:40 eric.smith set messages: +
2018-05-16 20:35:04 barry set messages: +
2018-05-16 20:09:21 eric.smith set messages: +
2018-05-16 19:56:39 barry set messages: +
2018-05-16 19:21:17 eric.smith set messages: +
2018-05-16 16:21:52 barry set priority: normal -> release blocker
2018-05-16 16:16:01 ned.deily set messages: +
2018-05-16 16:09:31 barry set nosy: + ned.deilymessages: +
2018-05-16 16:07:10 barry set messages: +
2018-05-16 16:02:42 eric.smith set messages: +
2018-05-16 15:10:27 barry set messages: +
2018-05-16 14:53:13 barry create