Introducing Record Types in Python

Can you elaborate on exactly what the advantages are, though? Remember that the bar for new syntax is very high.

1 Like

I totally feel the annoyance of having to type @dataclass immediately followed by an obvious class, but custom dataclass creators (either decorators or base classes) wouldn’t benefit from this special syntax. So not only would this special syntax prioritize dataclasses over atts, but over all custom dataclasses.

Can you not just wrap the dataclass decorator? Read the class, transform all the fields with default values, and then pass that transformed class to dataclasses.dataclass?

While we’re brainstorming about dataclasses, is there an easy way to elegantly make dataclasses call super for all ordinary base classes and __post_init__ for all dataclass base classes?

Currently, something like this monstrosity seems to be required?

@dataclass
class X(SomeBaseDataclass):
    def __post_init__(self) -> None:
        if hasattr(super(), '__post_init__'):
            super().__post_init__()  # type: ignore[misc] # pyright: ignore
        # Do whatever you planned to do.

I wonder if we could get most of the way towards what we want by introducing an alias for immutable dataclasses. Something like:

frozendataclass = dataclass(frozen=True, slots=True)

The idea being to require less boilerplate when wanting to encourage immutable programming. All of my dataclasses these days default to frozen=True and slots=True, following the concept that immutable-by-default is easier to reason about.

So then a user could simply:

from dataclasses import frozendataclass

@frozendataclass
class T:
    ...

The name could be bikeshedded of course, but the idea is to make a simpler alias for immutable dataclasses without having to reinvent an entirely new type that mirrors most of the usecases of dataclasses.

Would something like this be a more incremental approach to encouraging this kind of pattern without any new syntax or concepts?

2 Likes

I don’t know. It really feels like we already have too many ways to more/less do the same thing.

We have types.SimpleNamespace, typing.namedtuple, collections.namedtuple, dataclasses.dataclass, using a plain dict, doing it manually, and probably other ways I’m forgetting.

I understand we like syntactic sugar, but changing the core language when we already have all of the above seems to go against the zen at least:

Explicit is better than implicit.
..
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.

In the case of a dataclass I can be nice and explicit about its settings. With (yet) another way, I could be left guessing: Is it mutable, does it use __slots__, does it have __eq__?

I’d be interested in the PEP just to see the ‘how we teach this’ section. Like how can we possibly explain why all of these things exist along with this new way; especially to beginners?

2 Likes

From the OP’s list of benefits, what is the difference between this and TypedDict and using type hinting?

The underlying concrete object being a dictionary already has those benefits.

1 Like