On 19/10/2023 20.43, Dom Grigonis wrote:
On 19 Oct 2023, at 10:27, dn via Python-ideas <python-ideas@python.org> wrote:
On 19/10/2023 19.50, Dom Grigonis wrote:
Thank you,
Good information, thank you. Was not aware of __set_name__.
IIRC that was one of the updates/improvements. Thanks to whomsoever...!
The:
instance.__dict__[self.name] = value
may require a bit of thought before it feels comfortable, but it is
significantly easier to understand than what we had to do 'before'.
I am using `setattr(instance, self.name, value)`. But I see that
instance.__dict__ is more appropriate in this case.
IIRC that's the way we used to have to do things, ie 'turn ourselves in
knots'!
Because coding a Custom Descriptor is still something of a mind-bender,
I coded a 'library' ABC/Super-class ("something I put in the oven
earlier"*) which is slightly more sophisticated that the code-example
(see earlier) PLUS a call to, and outline-code for an @abstractmethod
called validate(). Care to guess its purpose!?
This means that when a Custom Descriptor is useful, it is a matter of
(trust and) sub-classing, eg NonNegativeInteger( SuperClassName ), which
provides an appropriate, concrete, validate() method.
"Re-use" = no fuss, no muss!
- more to the point, my future-self doesn't have to remember the
intricacies of the 'new' (v3.6+) internal mechanisms...
(the ABC is about 40-lines of code. I'll post it upon demand, or perhaps
better off-list...)
* this is a saying originating in (British) television cooking-shows, to
explain the temporal distortion of how the cook went from a mix of
uncooked ingredients to the finished article, without the waiting-time
for it to cook - as we would in real-life.
Another surprise, and I've assumed you're asking in the context of [Custom]
Descriptors, is in how many places/functions Python makes use of a
descriptor/descriptor protocol. Yet few of us seem to make use of them in our
application code...
(YMMV!)
I use them more and more.
+1
I use them to abstract-away almost all data-item data-validation.
However, I was more interested, why doesn't __set__ have an `owner` argument,
while `__get__` does. I am aware that this is not an issue at all as one can
simply do `inst.__class__`, but I am just curious about the reason for
inconsistency.
@Antoine has given a technical explanation.
The next contribution to your thinking is probably to mention/remind
that the "owner" argument (in the 'getter') is optional - can provide it
in __set_name__() and record it there. Thus, the effective-signatures
become:
def __get__( self, instance, )
...
def __set__( self, instance, value, )
...
Is this a more familiar pattern?
Perhaps the 'mistake' is not in an apparent lack of consistency, but in
our expectation of a 'tidy' pattern? There's always going to be a
difference in the two signatures, because the 'setter' must be provided
with a value, whereas the 'getter' returns (cf accepts) a data-value.
Still have questions?
Let's take a step (or two) backwards:-
Most of us start (down this road) by being introduced to @property. A
favorite (realistic) example is "age". Despite (sub-standard) text-books
featuring personnel records that use such a field, no professional ever
does! We record the person's date-of-birth, and thereafter compute the
difference from today() to arrive at (today's) age. The neat 'discovery'
is that when using object.age as a property, although the mechanism has
been coded as a method, its use is indistinguishable from a 'normal'
data-attribute. Smooth!
The next step in one's education is to add a 'setter'. The
tutorial-example here might be a physical quantity, eg how many
bars/tablets/blocks of chocolate you are buying (to give to me, of
course). This must be a positive number (there's a (in)famous Amazon bug
where they went 'live' allowing negative-quantities!!!). In the case of
chocolate, it might be an integer. In the case of other products it
might be a decimal/float, eg 1.5KG/lbs of flour. (yes, that would be to
mix-up a chocolate cake!).
This extension to the first @property use-case, is likely the
performance of some-sort of 'validation routine' to make sure that the
data is fit-for-purpose ("data-cleaning", "data-validation", etc). The
original @property mechanism swings into action when we ask for the
value. In this case, the mechanism applies when we set the data-value.
Thus, 5 is an acceptable quantity, but "five" is not - and the code is
designed to test for such.
You know all this, and that an @property is 'syntactic sugar' for a
Descriptor as the underlying mechanism.
So, now extend that final step, so that instead of an @property with
'getter' and 'setter', code the data-item (actually, its type) as a
Descriptor.
Now, remember that a data-item which is a Descriptor is just like any
other. To set its value, the code is:
instance.quantity = 1.5 # ie 1.5KG of flour
An "expression" where the name of the data-item is on the
left-hand-side, and the value is the RHS.
Whereas, when we come to utilise same, eg
line_price = quantity * unit_price
data-items on the RHS only need to be identified by their name!
So, the 'setter' provides two inputs - name and value.
Whereas, the 'getter' only needs to know which name (applies to that
data-item).
The 'pattern' or (necessary) consistency is only the name/id of the
data-item. Its value is 'inconsistent' in that it is either being
passed-in ('setter') or pulled-out ('getter'). In one case it is an
argument and in the other a return-value.
Although, answers that I got were very useful.
Thanks!
--
Regards,
=dn
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/24Z4FIPXPKGATDAXC6VPIRHTXP2WFXUF/
Code of Conduct: http://python.org/psf/codeofconduct/