I don’t like the idea of going back and fourth for positional and keyword arguments. The positional arguments have to stay at the top of some variable (be it anything, e.g, __pos: Any). The mixed stays in between the two markers. And the keyword arguments come after yet another predefined variable with leading dunder (e.g., __kw:Any). Please if you are going to do this for dataclasses, it has to match the function signature. This will be much easier for us to use, read, and teach. Going back and forth will cause a lot of confusion, as the order of the arguments in the init method will not follow the same order as the arguments defined in the dataclass. Thanks to whoever mentioned this in this email chain.
The thing is, even without being able to switch back and forth within a single dataclass, you could achieve the same thing with inheritance:
@dataclass(kw_only=True)
class Base:
a: int
b: int
@dataclass
class Derived(Base):
c: int
d: int
@dataclass(kw_only=True)
class MoreDerived(Derived):
e: int
f: int
Here, a, b, e, and f are keyword-only, and c and d are normal.
Likewise, you could do the same thing with:
@dataclass
class A:
a: int = field(kw_only=True)
b: int = field(kw_only=True)
c: int
d: int
e: int = field(kw_only=True)
f: int = field(kw_only=True)
In both cases, you'd get re-ordered fields in __init__, and
nowhere else:
def __init__(c, d, *, a, b, e, f):
repr, comparisons, etc. would still treat them in today's order:
a, b, c, d, e, f.
Other than putting in logic to call that an error, which I
wouldn't want to do, it would be allowable. Why not allow the
shortcut version if that's what people want to do? Again, I'm not
saying this needs to be a day one feature using "__kw_only__:
ArgumentMarker" (or however it's ultimately spelled). I just don't
want to rule it out in case we come up with some reason it's
important.
I just checked and attrs allows that last case:
@attr.s
class A:
a = attr.ib(kw_only=True)
b = attr.ib(kw_only=True)
c = attr.ib()
d = attr.ib()
e = attr.ib(kw_only=True)
f = attr.ib(kw_only=True)
Which generates help like:
class A(builtins.object)
| A(c, d, *, a, b, e, f) -> None
The main reason to allow the switching back and forth is to support subclassing dataclasses that already have normal and keyword-only fields. If you didn't allow this, you'd have to say that the MostDerived class above would be an error because the __init__ looks like the parameters have been rearranged.
And the same logic would apply to positional argument fields.
I just don't see the need to prohibit it in general. Any tutorial
would probably show the fields in the order you describe above:
positional, normal, keyword-only.
Eric
Abdulla
Sent from my iPhone
On 13 Mar 2021, at 9:30 PM, Paul Bryan <pbryan@anode.ca> wrote:
+1 to Matt's points here. I get the desire for symmetry with / and * in params, but I'm not convinced it's useful enough to warrant the complexity of the approaches being proposes. I think a @dataclass(..., kwonly=True) would solve > 90% of the issues with dataclass usability today.
On Sat, 2021-03-13 at 06:41 -0500, Matt Wozniski wrote:On Fri, Mar 12, 2021, 11:55 PM Eric V. Smith <eric@trueblade.com> wrote:
There have been many requests to add keyword-only fields to dataclasses.
These fields would result in __init__ parameters that are keyword-only.
As long as I'm doing this, I'd like to add positional-only fields as well.
Have there also been requests for positional-only fields?
The more I digest this idea, the more supporting positional-only fields sounds like a bad idea to me. The motivation for adding positional-only arguments to the language was a) that some built-in functions take only positional arguments, and there was no consistent way to document that and no way to match their interface with pure Python functions, b) that some parameters have no semantic meaning and making their names part of the public API forces library authors to maintain backwards compatibility on totally arbitrary names, and c) that functions like `dict.update` that take arbitrary keyword arguments must have positional-only parameters in order to not artificially reduce the set of keyword arguments that may be passed (e.g., `some_dict.update(self=5)`).
None of these cases seem to apply to dataclasses. There are no existing dataclasses that take positional-only arguments that we need consistency with. Dataclasses' constructors don't take arbitrary keyword arguments in excess of their declared fields. And most crucially, the field names become part of the public API of the class. Dataclass fields can never be renamed without a risk of breaking existing users. Taking your example from the other thread:
```@dataclasses.dataclassclass Comparator:a: Anyb: Any_: dataclasses.KEYWORD_ONLYkey: Optional[Callable[whatever]] = None```
The names `a` and `b` seem arbitrary, but they're not used only in the constructor, they're also available as attributes of the instances of Comparator, and dictionary keys in the `asdict()` return. Even if they were positional-only arguments to the constructor, that would forbid calling
comp = Comparator(a=1, b=2, key=operator.lt)
but it would still be possible to call
comp = Comparator(1, 2, key=operator.lt)print(comp.a, comp.b)
Preventing them from being passed by name to the constructor seems to be adding an inconsistency, not removing one.
Perhaps it makes sense to be able to make init-only variables be positional-only, since they don't become part of the class's public API, but in that case it seems it could just be a flag passed to `InitVar`. Outside of init-only variables, positional-only arguments seem like a misfeature to me.
~Matt_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/LPUHXVDHW7QQR4KNOQQTNWT6UJ2CHDBI/
Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@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/DWMTQCOHZG233R5POM74RUTOYP3AV6FH/
Code of Conduct: http://python.org/psf/codeofconduct/
-- Eric V. Smith