[issue39247] dataclass defaults and property don't work together

Thomas report at bugs.python.org
Thu Oct 21 18:12:24 EDT 2021


Thomas <thomas.d.mckay at gmail.com> added the comment:

Agreed on everything but that last part, which I'm not sure I understand:
> If we allow descriptor to accept an iterable as well you could have multiple descriptors just like normal.
Could you give an example of what you mean with a regular class?

I've had a bit more time to think about this and I think one possible solution would be to mix the idea of a "descriptor" argument to the field constructor and the idea of not applying regular defaults at __init__ time.


Basically, at dataclass construction time (when the @dataclass decorator inspects and enhances the class), apply regular defaults at the class level unless the field has a descriptor argument, then apply that instead at the class level. At __init__ time, apply default_factories only unless the field has a descriptor argument, then do apply the regular default value.

If the implementation changed in these two ways, we'd have code like this work exactly as expected:

from dataclasses import dataclass, field


@dataclass
class Foo:
    _bar: int = field(init=False)
    
    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value
    
    # field is required,
    # uses descriptor bar for get/set
    bar: int = field(descriptor=bar)

    # field is optional,
    # default of 5 is set at __init__ time
    # using the descriptor bar for get/set,
    bar: int = field(descriptor=bar, default=5)

    # field is optional,
    # default value is the descriptor instance,
    # it is set using regular attribute setter
    bar: int = field(default=bar)

Not only does this allow for descriptor to be used with dataclasses, it also fixes the use case of trying to have a descriptor instance as a default value because the descriptor wouldn't be used to get/set itself.

Although I should say, at this point, I'm clearly seeing this with blinders on to solve this particular problem... It's probable this solution breaks something somewhere that I'm not seeing. Fresh eyes appreciated :)

----------

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue39247>
_______________________________________


More information about the Python-bugs-list mailing list