On Fri, Mar 12, 2021, 11:55 PM Eric V. Smith <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)

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-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/LPUHXVDHW7QQR4KNOQQTNWT6UJ2CHDBI/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to