Repository navigation
Add kwarg-only option to dataclass #77310
Description
Activity
I'd like to request a new option to the
dataclasses.dataclassdecorator to make the__init__keyword-only.The two use-cases I have in mind are:
(1) Using as a dataclass big-bag-of-config. In this scenario, forcing the user to specify the keywords is a lot nicer than passing in a dozen positional parameters.
(2) Having kwarg-only parameters means that inheritance and default parameters play nicely with each other again instead of raising a TypeError.
- added3.7 (EOL)end of lifeend of life3.8 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement
on Mar 23, 2018 If this would be accepted, I'd be happy to contribute a patch adding a
kwarg_onlyoption todataclass(although it might take me a while since I'm not super familiar with the Python development workflow). I believe I already have the code change necessary at alanhdu@fa35b39 (although it still needs tests and documentation).Err... the right link would actually be https://github.com/alanhdu/cpython/tree/bpo-33129.
Changing this to 3.8: there's not enough time to add this to 3.7.
I'd forgotten about this issue and created bpo-33493. I'll close it. Copied here is my comment from that issue:
I've had several requests for keyword-only arguments. This is a placeholder to remind me to work on it. I have not decided if it's a good idea or not.
I propose adding a keyword_only argument to field(), defaulting to False.
I'm thinking that the basic idea would be to put all keyword-only fields at the end of the arguments to __init__, but for all other uses, leave them where they appear in the class definition. That way comparison operations, in particular, would use the fields as they appear in the class definition (which is the current behavior). Since they'd be at the end of __init__, and since order doesn't matter (they're keyword-only, after all), then this would work as expected for base classes.
That is, given:
@dataclass class B: a: field(type=int, keyword_only=True) b: int @dataclass class C(B): c: int d: field(type=int, keyword_only=True)
Then B's __init__ would take (b, c, *, a, d) as its arguments, but its comparison functions would compare the tuples as (a, b, c, d).
It would be an error for a ClassVar field to be keyword-only. I think it would be okay if an InitVar field were keyword-only, but I haven't given it a lot of thought.
There is an open PR and some discussion about this feature in attrs repo : python-attrs/attrs#281
+1 from me -- think would occasionally be nice to have.
first post in bugs.python.org... are people normally scary around here?
Another usecase of keyword-only arguments is that I can mix default and non-default fields in any order. This could be achieved by either marking all fields as read-only, or by implicitly adding an asterisk before the first "conflicting" non-default argument (or by translating .../etc into an asterisk).
(Is it a bad idea to create a private fork of
pip install dataclasseswith implicit asterisk, purely for my own project?)Hello! I've submitted a PR based on this issue, since it seemed the most relevant from my searching of the backlog.
Here's a link: #19206
Hi,
As another piece of evidence: I run into this problem _all the time_. Whenever I need a field in the parent with a default, I either need to add bogus default values for every field in every subclass or just skip the default in the parent.
I'd like to suggest a middle ground:
- A field level keyword_only option which forces just that field to be a kw-only field (for every subclass as well).
- A class level keyword_only option that does:
2a. False (default) means current behavior where classes are not keyword only (but may be forced to be by the field specific arg).
2b. True means all the fields in this class (but not the subclasses!) Would be marked as keyword only. This does affect the order of arguments in the init method but that seems acceptable given that keyword only parameters are conceptually order independent.
2c. None implies that precisely the fields with a default (or default_factory) should be keyword only fields.
Thoughts?
Since '/' was introduced in Python 3.8, support for positional parameters should be supported too.
conchylicultor commented
on Nov 11, 2020 conchylicultormannequinMannequinMore actionsSolving this would significantly improve @DataClass inheritance (https://bugs.python.org/issue39300). Any idea when this will land ?
Currently, it is not possible to add required argument to a child dataclass (unless hacks like duplicating attributes):
import dataclasses @dataclasses.dataclass class A: x: int = 1 @dataclasses.dataclass class B(A): y: int # ERROR: non-default argument follows default argumentKeywords-only would solve this issue:
@dataclasses.dataclass class B(A): y: int = dataclasses.field(kw_only=True) B(123, y=456)Note: Attrs already support this: https://www.attrs.org/en/stable/examples.html#keyword-only-attributes
For the behavior, I think there are two options:
class A: a0: int a1: int = field(kw_only=True) a2: int class B(A): b0: int b1: int = field(kw_only=True) b2: intOption 1: All attributes following
kw_onlyarekw_only(kw_only indicates where to place '*')A(a0, *, a1, a2) B(a0, b0, *, a1, a2, b1, b2)
Option 2:
kw_onlyare individually moved to the endA(a0, a2, *, a1) B(a0, a2, b0, b2, *, a1, b1)
I personally prefer Option 1, as it makes it easier to place the
*with less boilerplate.class Request: url: str timeout: int = field(default=-1, kw_only=True) verify: bool = False params: Optional[Dict[str, str]] = None cookies: Optional[Dict[str, str]] = None Request(url, *, timeout=-1, verify=False, params=None, cookies=None)Which looks better than:
class Request: url: str timeout: int = field(default=-1, kw_only=True) verify: bool = field(default=False, kw_only=True) params: Optional[Dict[str, str]] = field(default=None, kw_only=True) cookies: Optional[Dict[str, str]] = field(default=None, kw_only=True)conchylicultor commented
on Dec 16, 2020 conchylicultormannequinMannequinMore actionsFor the API, I think we could add this feature with a single new
dataclass(kw_only: bool | str)@dataclasses.dataclass(kw_only=True) class A: a: int b: int c: int # A(*, a, b, c) @dataclasses.dataclass(kw_only='b') class A: a: int b: int c: int # A(a, *, b, c)I think this would be flexible enough for all use cases, while avoiding the boilerplate from the above proposals.
Closing this in favor of bpo-43532, which has a slightly elaborated approach.
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: