implementing descriptors

Dave Angel davea at ieee.org
Fri Aug 14 16:48:00 CEST 2009


dippim wrote:
> On Aug 14, 2:34 am, Raymond Hettinger <pyt... at rcn.com> wrote:
>   
>> [David]
>>
>>
>>
>>     
>>> I am new to Python and I have a question about descriptors.  If I have
>>> a class as written below, is there a way to use descriptors to be
>>> certain that the datetime in start is always before the one in end?
>>>       
>>> class foo(object):
>>>    def __init__(self,a =one,b = None)
>>>       self.start =
>>>       self.end =
>>>       
>>> from datetime import datetime
>>> c =atetime(2009,8,13,6,15,0)
>>> d =atetime(2009,8,14,12,0,0)
>>> afoo =oo(c,d)
>>>       
>>> For instance, if the following code were run, I would like to instance
>>> of foo to switch the start and end times.
>>>       
>>> afoo.start =atetime(2010,8,13,6,15,0)
>>>       
>>> I was thinking of using the __set__ descriptor to catch the assignment
>>> and reverse the values if necessary, but I can't figure out how to
>>> determine which values is being set.
>>>       
>> You're on the right track, but it is easier to use property() than to
>> write your own custom descriptor with __get__ and __set__.
>>
>> class foo(object):
>>     def __init__(self,a =one,b = None):
>>         self._start =
>>         self._end =
>>     def get_start(self):
>>         return self._start
>>     def set_start(self, value):
>>         if self._end is None or value < self._end:
>>             self._start =alue
>>         else:
>>             self._end =alue
>>     start =roperty(get_start, set_start)
>>     def get_end(self):
>>         return self._end
>>     def set_end(self, value):
>>         if self._start is None or value > self._start:
>>             self._end =alue
>>         else:
>>             self._start =alue
>>     end =roperty(get_end, set_end)
>>
>> Raymond
>>     
>
> Raymond,
>    This functionality is exactly what I was looking for. Thanks!  I'll
> be using this to solve my problem.
>
>    Now that I'm on the right track, I'm still a bit confused about how
> __get__ and __set__ are useful.  Admittedly, I don't need to
> understand them to solve this problem, but perhaps they may be useful
> in the future.  If I wanted to solve this problem using __get__ and
> __set__ could it be done?
>
> Thanks Again!
>
>   
DANGER- WILL ROBINSON!

Don't use this code as-is.  There is a nasty surprise waiting for the 
caller when he sets start and end, and discovers that one of them gets 
thrown out, and an old value still remains.

obj= foo(3, 5)
obj.start = 8
obj.end = 12
print obj.start, obj.end

will print out  3, 12.    Not what the caller expected.

Four fixes, in order of preference:
0) Trust your user to read and obey your docstrings.  This was what JM 
was implying, by changing the names of the formal parameters.
1)  make a new method that sets both values, making these two properties 
readonly.  That new method would make sure the two parameters are 
self-consistent.  Making the actual values readonly can be done with a 
descriptor as well, or even a decorator.
2) Raise an exception in the getter methods if they're out of order
3) do the min/max logic on the getter methods, but I don't like that one 
at all.

DaveA




More information about the Python-list mailing list