Tkinter callback arguments

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Wed Nov 4 08:37:14 CET 2009


En Wed, 04 Nov 2009 03:15:14 -0300, Alf P. Steinbach <alfps at start.no>  
escribió:
> * Steven D'Aprano:
>> On Wed, 04 Nov 2009 02:29:21 +0100, Alf P. Steinbach wrote:
>>
>>>>> For example, consider two rectangle classes R1 and R2, where R2 might
>>>>> be a successor to R1, at some point in system evolution replacing R1.
>>>>> R1 has logical data members left, top, width and height, and R2 has
>>>>> logical data members left, top, right and bottom. With R1 direct
>>>>> changes of left and top keeps the rectangle's size (since that size  
>>>>> is
>>>>> specified by width and height), while with R2 it changes the
>>>>> rectangle's size. R1 is implemented with logical data members as
>>>>> directly exposed data attributes. Some code in the system deals only
>>>>> with R1 objects and for convenience or efficiency or whatever uses
>>>>> direct modification instead of set_position method. Due to new
>>>>> requirements it instead has to deal with R2 objects, with same
>>>>> methods. But due to the direct modification of object state it now
>>>>> changes the rectangle sizes, but at first it's not noticed since the
>>>>> attempted rectangle position changes are very small. People get  
>>>>> upset.
>>>>> The bug is fixed. Time has been wasted.
>>>> If there is need for mutable rectangles, there is need for mutable
>>>> rectangles. Using properties instead of attributes doesn't help
>>> In the example above using properties would have avoided the problem.
>>  How would it have avoided the problem? Either of these would have the  
>> exact same semantics:
>>  class R2(object):
>>     def __init__(self):
>>         self._secret = {'top': 0, 'bottom': 100}
>>     def _top_getter(self):
>>         return self._secret['top']
>>     def _top_setter(self, value):
>>         self._secret['top'] = value
>>     top = property(_top_getter, _top_setter)
>>  vs
>>  class R2(object):
>>     def __init__(self):
>>         self.top = 0
>>         self.bottom = 100
>
> OK, I had a laugh. :-) You maintain that all doors are dark red, and  
> show up a photo of two of your dark red doors as proof.
>
> For R2, did you at *any* moment consider properties that emulated the  
> internal representation of R1?
>
> I'm putting it that way on the off-chance that you're not just  
> pretending to not understand.

I don't understand either. R1 and R2 have *different* semantics. They  
don't behave the same. Any breakage you experiment using R2 instead of R1  
comes from the fact they behave differently, not because they're  
implemented differently, nor because they use properties or not.
You could have implemented another variant, let's say RCrazy, that behaves  
exactly the same as R1 but internally stores a different set of attributes  
(the baricenter, the angle between both diagonals, and the diagonal  
length). As long as you implement the same public interfase (same set of  
externally visible attributes, same methods, same behavior) RCrazy is  
interchangeable with R1; RCrazy is a subtype of R1 in the sense of the  
Liskov substitution principle.
Of course, perfect substitutability (did I spell it right?) isn't possible  
in Python; obj.__class__.__name__ returns 'RCrazy' instead of 'R1', it's  
mro() is different, dir() returns a different set of names, etc. But for  
any `reasonable` use of an R1 instance representing a rectangle, an RCrazy  
instance should serve equally well.

>> Given the semantics you specified
>
> No semantics was specified in my example, quoted in full above.
>
> However, the natural semantics is that various logical properties, such  
> as left, top, right, bottom, width and height, can be varied  
> independently.

You did specify the set of attributes and how they behave, perhaps not  
very formally, but that's a semantic specification to me. It was clear  
 from your description that R2 behave different that R1; the problems that  
came after using R2 instead of R1 were caused by such different behavior,  
not because of using properties or not. In any case, I don't think the  
problem is specific to Python.

>> it is strictly irrelevant whether R2.top is an attribute or a property.  
>> That's an implementation detail.
>
> Happily that's incorrect. You might try to consider what properties are  
> *for*, why the language supports them if they do nothing at all except  
> adding overhead.

In normal usage (either obj.name or getattr(obj, 'name')) an attribute is  
undistinguishable from a property. Users of the class should not worry at  
all whether it is implemented as a simple attribute, a computed property,  
or an esoteric class attribute following the descriptor protocol.
If all a property does is to store and retrieve its value as an instance  
attribute, yes, it just adds overhead.

-- 
Gabriel Genellina




More information about the Python-list mailing list