Thanks Eric.

That's a really good summary of the ideas thrown around up to this point in the other thread. I'm not overly fussed about the precise syntax we use, though I do have a preference for using an extra level of scope to mark fields as pos/kw only, either with context managers or with nested classes like Matt Woznisky suggested (because I think this makes it more explicit and and less surprising to someone seeing it for the first time). But that's not a hill I'd even remotely consider dying on.

As long as we get:
1) positional-only and keyword-only arguments for dataclasses
2) in an inheritance-friendly way that allows subclasses to also specify their own respective normal/positional/kw fields

I'll be happy.

As I understand it your proposal would allow for the following, right?

import dataclasses


@dataclasses.dataclass
class Parent:
pos = dataclasses.POS_ARG
a: int

normal = dataclasses.NORMAL_ARG
c: bool = False

kw = dataclasses.KW_ARG
e: list


@dataclasses.dataclass
class Child(Parent):
pos = dataclasses.POS_ARG
b: float = 3.14

normal = dataclasses.NORMAL_ARG
d: dict = dataclasses.field(default_factory=dict)

kw = dataclasses.KW_ARG
f: set = dataclasses.field(default_factory=set)

Producing an __init__ like:

def __init__(self, a: int, b: float = 3.14,
/, c: bool = False, d: dict = None,
*, e: list, f: set = None):
That is to say, you can specify these special values once per class in the inheritance hierarchy (not just once overall) and the fields in each category get added on at the end of that category (normal/pos/wk) compared to the parent's __init__ signature.

If so, I'm happy with this.


PS:

I do think there will be some confusion around unexpected behaviour when someone who has seen this many times:

@dataclasses.dataclass
class Example:
_ = dataclasses.KW_ARG
a: str

tries this and is confused as to why it doesn't work as expected:

@dataclasses.dataclass
class Example:
_ = dataclasses.POS_ARG
a: str
_ = dataclasses.KW_ARG
b: int
Basically, the requirement that the names these special values are assigned to must be unique is an unfortunate side-effect of the fact that Python doesn't bind free-floating objects to locals in some way, the way it does with for type hints into __annotations__ which would allow the much cleaner:
@dataclasses.dataclass
class Example:
dataclasses.POS_ARG
a: str
dataclasses.KW_ARG
b: int
Come to think of it, this would make certain declarative constructs like those found in SQLAlchemy much cleaner as well, but that's a proposal for a different thread :p

On Sat, Mar 13, 2021 at 9:50 AM Eric V. Smith <eric@trueblade.com> wrote:

Sorry, Matt: I meant to credit you by name, but forgot to during my final edit.

I still don't like the verbosity and the look of 'with' statements or classes. Or the fact that some of the fields are indented relative to others.

And should also mention that Ethan Furman suggested using '*' and '/' as the "type", in https://mail.python.org/archives/list/python-ideas@python.org/message/BIAVX4O6JRPQY7S3XG2IX6BSBZLAR2NS/ , although the interaction with typing (specifically get_type_hints) might be an issue:

    class Hmm:
        #
        this: int
        that: float
        #
        pos: '/'
        #
        these: str
        those: str
        #
        key: '*'
        #
        some: list

Anyway, Matt's and Ethan's proposal are on the other thread. I'd like to keep this thread focused on my proposal of dataclasses.KW_ONLY and .POS_ONLY. Not that saying "I'd like focus this thread" has ever worked in the history of python-ideas.

Eric

On 3/13/2021 2:40 AM, Matt Wozniski wrote:
On Fri, Mar 12, 2021, 11:55 PM Eric V. Smith <eric@trueblade.com> wrote:
I should mention another idea that showed up on python-ideas, at
https://mail.python.org/archives/list/python-ideas@python.org/message/WBL4X46QG2HY5ZQWYVX4MXG5LK7QXBWB/
. It would allow you to specify the flag via code like:

@dataclasses.dataclass
class Parent:
     with dataclasses.positional():
         a: int
     c: bool = False
     with dataclasses.keyword():
         e: list

I'm not crazy about it, and it looks like it would require stack
inspection to get it to work, but I mention it here for completeness.

I think stack inspection could be avoided if we did something like:

```
@dataclasses.dataclass
class Parent:
     class pos(dataclasses.PositionalOnly):
         a: int
     c: bool = False
     class kw(dataclasses.KeywordOnly):
         e: list
```

Like your proposal, the names for the two inner classes can be anything, but they must be unique. The metaclass would check if a field in the new class's namespace was a subclass of PositionalOnly or KeywordOnly, and if so recurse into its annotations to collect more fields.

This still seems hacky, but it seems to read reasonably nicely, and behaves obviously in the presence of subclassing.

_______________________________________________
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/IFE35VNDZH5YUNXY23I53QBDCUFB7GRQ/
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-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/4N2NOOXZBP5HF66N3OXD7CZ3HCGD3SLV/
Code of Conduct: http://python.org/psf/codeofconduct/