Ah, very interesting.

Just tried this and it worked. That's awesome, thanks!

On Mon, Jan 4, 2021, at 15:45, Joao S. O. Bueno wrote:
> I think you are complicating things just because there is no easy way 
> to tell mypy
> that although you are assigning a descriptor to a class variable
> in the class body, it will be used as a normal instance attribute 
> afterwards - and
> it is the type used in the instance attribute that mypy should care for,
> 
> And then 
> maybe, the specs of static type checking could get a feature to allow
> assigning one thing at class declaration and another thing at instance working
> (otherwise, not only dataclasses, but anything using custom descriptors
> would not work with static type checking).
> 
> As a workaround, you could just "cast" our descriptor instance to the
> type the attribute will actually hold - mypy should not complain:
> ```
> @dataclass
> class Item:
>     price: Decimal = typing.cast(Decimal, MyDescriptor())
> 
> ```
> 
> On Sun, 3 Jan 2021 at 22:48, Josue Balandrano Coronel 
> <j...@rmcomplexity.com> wrote:
> > 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/
> _______________________________________________
> 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/HRIDJO4VX4F4MNOHODMZJNAOV7NP2VL7/
> Code of Conduct: http://python.org/psf/codeofconduct/
>

-- 
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/7CFKKYMVEUQV545R4DWXQOPC2F6UJMCY/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to