5

I'd like to use @dataclass to remove a lot of boiler plate, but I also like the data encapsulation offered by @property. Can I do both simultaneously?

As a toy example, I have a class like

class Breakfast:

    def __init__(self, sausage: str, eggs: str = "Scrambled", coffee: bool = False):
        self._sausage = sausage
        self._eggs = eggs
        self._coffee = coffee

    @property
    def sausage(self):
        return self._sausage

    @property
    def eggs(self):
        return self._eggs

    @property
    def coffee(self):
        return self._coffee

    def __repr__(self):
        ...

    def __eq__(self):
        ...

where I may also have setters for some of properties. What I'd like, is to write this in some form like this

@dataclass(property=True)
class DataBreakfast:
    sausage: str
    eggs: str = "Scrambled"
    coffee: bool = False

(where, of course, my decorator argument doesn't work) that would do all the routine stuff that @dataclass does, and essentially outputs the code of the first snippet. I could then manually add setters in the rest of the class body at my leisure.

This seems like a common enough use case, but I couldn't figure out a way of getting it to work. The frozen parameter is the closest to what I want, but it doesn't really behave like @property as it precludes any kind of setter.

14
  • 1
    I can't find a way to write a solution that feels like it reduces the amount of work for your use-case. If all you want is read-only by default, there is frozen, or, of you only want it on some fields, semi. If you want to skip writing the @property, and only want to add a getter sometimes, you're out of luck because you're going to get a type-error while the class-body is parsed, even before the dataclass-decorator gets to apply its logic. And if you want to add logic like an access-counter, you'll have to write the property anyway.
    – Arne
    Commented May 17, 2021 at 8:06
  • 1
    The only thing that I can get to work reasonably is "use properties under the hood, but without any special code inside. and if you try to mess with it, like adding a getter retroactively, everything will break", which doesn't seem useful at all.
    – Arne
    Commented May 17, 2021 at 8:07
  • 2
    Just in case you haven't stumbled over it yet, here is a blog post on using dataclasses with properties. Using a dataclass doesn't reduce the amount of work there, but you still do get all the other things like __repr__ for free.
    – Arne
    Commented May 17, 2021 at 11:34
  • 1
    Sounds like you want to use field properties. I'd take a look at this article as it might provide you some clarification: dataclass-wizard.readthedocs.io/en/latest/… Commented Aug 30, 2021 at 16:33
  • 1
    Apologies, jsut going through and re-reading the section above. only issue I see with auto-property approach is that IDE won't know what @foo.setter means (won't be able to offer any completion hints). Of course its simple enough to define your own metaclass that automatically converts every dataclass field to a property, and would likely be the approach that I suggest for now (unless dataclasses adds this kind of support somewhere down the road) Commented Aug 30, 2021 at 17:30

0

Browse other questions tagged or ask your own question.