New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@dataclass defaults #82939
Comments
Given one of the motivations of @DataClass is to reduce boilerplate code then, in the context of @DataClass, x: list = [] should be equal to x: list = field(default_factory=lambda: []) The example in PEP-557 is not reasonable. It should be: class D:
def __init__(self, x=[]):
self.x = x That x = None works (without specifying a default factory, and is different from plain "x") makes the whole "factory" argument even more bizarre. Why would a None Type work, but a List Type not? I think either the behavior of this should be different or the docs should at address this more clearly. |
Have you read ericvsmith/dataclasses#3? |
Thanks for adding it, I read it now. And sorry to back track a moment - I love the idea of @DataClass and I can I'm looking at this primarily from the narrow view point of a user - not so When using the default construction method it seems reasonable to pass a Let's imagine for a moment that @DataClass becomes the default way of Looking at Guido's first comment on this, I think that detection mechanism From a beginners perspective here, It would appear that in a sense the What about something like this: Issue #3 has many comments around copying, but that's not my concern, I'm I did the above example in regular python since I don't know enough about On Wed, Nov 13, 2019 at 10:11 AM Vedran Čačić <report@bugs.python.org>
|
To clarify, On Wed, Nov 13, 2019 at 1:04 PM Anthony Sarkis <anthonysarkis@gmail.com>
|
The problem is that what you wrote isn't what most people want. Here's your example without dataclasses. I've added an "append_to_x" method, which does the obvious thing: >>> class C:
... def __init__(self, x=[]):
... self.x = x
...
... def append_to_x(self, val):
... self.x.append(val)
...
Now create two objects, and inspect their "x" properties:
>>> a = C()
>>> b = C()
>>> a.x
[]
>>> b.x
[]
So far so good. Now append something to "a.x":
>>> a.append_to_x(10)
>>> a.x
[10]
And notice that "b.x" changes, too:
>>> b.x
[10] So the naive behavior isn't what you want. dataclasses is trying to prevent you from doing this. You should look at "mutable defaults", perhaps starting here (from a random Google search): https://blog.florimond.dev/python-mutable-defaults-are-the-source-of-all-evil |
Hey Eric, I think our emails crossed in the wind, please see my comment that includes (as a sub component) a similar idea to what's proposed in the article you linked. |
I'm not sure what you're proposing. |
It seems to me that what you're missing is that "class declarations" are still perfectly normal executable statements (in most other superficially similar programming languages, they are not). So, when you say class A:
b = [] it is actually executed, a new empty list is made, and named A.b. If you then construct a = A(), then a.b is that same object. It must be, you never made any other list in the process. So if you really want a.b to be a _different_ empty list, you have to make it at some point. The most obvious way to do it is just to copy the A.b --- that's why people usually talk about copying. Your approach is different: it seems to me that you say, if A.b is a list, then make a new empty list, if it is a set, then make a new empty set, and if it is a dict, then make a new empty dict. Not to mention that it feels very weird when having e.g. class A:
b = [4] (-:, it doesn't take into account any other types. Which leads to another your problem, the one of perspective. Lists, sets and dicts are not that "common case" as you seem to think. Yes, they are in the beginners' code -- and that's why current dataclass implementation flags them as errors, since it's quite possible that people who write such things don't actually understand how Python is executed. But specialcasing them to actually do something useful would be the wrong thing to do, since it would incentivize people who should know better, back into using those simple types. I think it is shown in the discussion mentioned. |
I concur with Vedran and recommend this proposal be rejected. During training and code review, we spend a lot of time trying to get people to not write code like this. By making dataclasses behave differently than the rest of language, we would would lose the clear, bright line we have now. IOW, this would be bug bait. |
Vedran thank you for the detailed comments. I want to separate the idea side and implementation: Specifically that or more generally that I agree there's a lot lacking in my example starting point implementation. The scope of that example is meat to illustrate creating a default that is of least surprising, specifically that a new instance of a class is isolated. If a motivation for using type annotations is to restrict to reduce errors. To me, "prototyping" defaults by having them declared as soon as possible in the class is a further restriction. I believe that's a reasonable coding practice, and actually a good thing. To me this is the current situation, in order to setup a class using @DataClass a user must either: a) Have a relatively in depth understanding of python. I think proofs of that include both PEP having to have a section justifying that. And that there was such discussion in the issue. b) Calling two "special" / additional functions and adding a (relatively) large amount of code. I can't think of anything else in python where the default method requires knowing two separate additional functions! Python is all about short, semantically meaningful expressions yet this feels like the total opposite! If setting up defaults is a common point of error or "bad code" then why not setup the standard library in such a way that it does it right? This is my first attempt at a contribution, even if all it is is highlighting a problem and the "solution" I'm suggesting may be the wrong one. But so far all of comments feel like they are defending a cascade of "not ideal" situations. Let's try actually looking at the root from the user's perspective and how can we improve this! |
This should not have been an issue but a discussion on python-list or perhaps python-ideas. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: