I forgot to add:
I'm uncertain about your suggestion of a required order of fields, based
on argument type. I'll have to think about it some more. I'm working on
a sample implementation, and I'm going to wait and see how it works
before putting much more thought into it.
Eric
On 3/13/2021 3:14 PM, Eric V. Smith wrote:
On 3/13/2021 2:51 PM, Abdulla Al Kathiri wrote:
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 <pbr...@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 <e...@trueblade.com
<mailto:e...@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.dataclass
class Comparator:
a: Any
b: Any
_: dataclasses.KEYWORD_ONLY
key: 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 <http://operator.lt>)
but it would still be possible to call
comp = Comparator(1, 2, key=operator.lt <http://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
<mailto:python-ideas@python.org>
To unsubscribe send an email to python-ideas-le...@python.org
<mailto:python-ideas-le...@python.org>
https://mail.python.org/mailman3/lists/python-ideas.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/LPUHXVDHW7QQR4KNOQQTNWT6UJ2CHDBI/
<https://mail.python.org/archives/list/python-ideas@python.org/message/LPUHXVDHW7QQR4KNOQQTNWT6UJ2CHDBI/>
Code of Conduct: http://python.org/psf/codeofconduct/
<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/DWMTQCOHZG233R5POM74RUTOYP3AV6FH/
Code of Conduct: http://python.org/psf/codeofconduct/
--
Eric V. Smith
_______________________________________________
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/YQHFISC6LPS2UEWPONMED2C6ETM65WD3/
Code of Conduct: http://python.org/psf/codeofconduct/
--
Eric V. Smith
_______________________________________________
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/OVY4PWPDYNY6UXXLLPTUMNFDOJOMC3WZ/
Code of Conduct: http://python.org/psf/codeofconduct/