I've been exploring dataclasses for a few months now and they've proven to be 
very useful.

The only downside is that there's not a simple way to use descriptors.

Descriptors only work on class attributes (as per the docs: 
https://docs.python.org/3/howto/descriptor.html#closing-thoughts). This means 
that to use a descriptor in a data class we have to use typing.ClassVar like 
this

@dataclass
class Item:
    name: str
    price: typing.ClassVar[Decimal] = PriceValidator()

Which is totally fine because of how descriptors work the previous syntax is a 
feature in dataclasses, IMHO.

But, there's not a straight forward way to pass a value to the descriptor on 
init. Because ClassVars are not used by @dataclass to do its thing (as per the 
docs: https://docs.python.org/3/library/dataclasses.html#class-variables)

This means that in the example above `price` is not going to be a parameter of 
the class Item's __init__ method. So the only way to do this is to either 
create an InitVar field or a regular field and then pass the value to the 
descriptor in __post_init__

@dataclass
class Item:
    name: str
    price_val: InitVar[Decimal]
    price: typing.ClassVar[Decimal] = PriceValidator()

    def __post_init__(self, price_val: Decimal) -> None:
        self.price = price_val

When using a regular field we can double the field's purpose by making it the 
field the descriptor is going to use:

@dataclass
class Item:
    name: str
    _price: Decimal
    price: typing.ClassVar[Decimal] = PriceValidator()

    def __post_init__(self) -> None:
        self.price = self._price

And then in the descriptor implement __set_name__ like so:

def __set_name(self, owner, name):
    self.name = f"_{name}"


Personally, I don't like either option because it adds noice to the data class 
definition. Using an InitVar is the better option because that variable is 
clearly defined as init only and it's not present in an instance. Using a 
regular field adds unnecessary noice to the data class.

Also, I think it clashes with the intent of descriptors since they're supposed 
to manage their data in any way they want.

My questions are:

- Are my assumptions correct?
- Is this the intended behavior? Or what's the preferred way of using a 
descriptor in a dataclass field?
- If this is not intended, could it be possible to add a `descriptor` parameter 
to the `field` method and treat the field accordingly?

I couldn't find any information on the docs or the PEP. I could"ve missed 
something, sorry if this is the case :)

Thanks!

--
Josue
https://www.rmcomplexity.com
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/UOMBDIVNRG3DS6UHWSOF4JTLIPXEENCT/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to