Subclass sadness (was Re: [Python-Dev] PEP 285: Adding a bool type)

Alex Martelli aleax at aleax.it
Mon Apr 1 15:23:07 EST 2002


Aahz wrote:

> In article <DlTp8.48032$S52.1614804 at news2.tin.it>,
> Alex Martelli  <aleax at aleax.it> wrote:
>>
>>Actually, this specific problem is there, like several others, only
>>*for MUTABLE objects*.  Take an "immutable" rectangle:
        ...
>>class ImmutableRectangle(object):
>>    def __init__(self, width, heigth):
>>        object.__setattr__(self, 'width', width)
        ...
[I think I forgot to override __delattr__ and raise a
TypeError to shore up the immutability, forgot to
override __eq__ as a hashable should, etc, but anyway,
I hope the concept of immutability _is_ clear, even
though I messed some details up:-)]
        ...
>>Now, subclassing this is perfectly fine:
>>
>>class ImmutableSquare(ImmutableRectangle):
>>    def __init__(self, side):
>>        ImmutableRectangle.__init__(self, side, side)
> 
> Where is the side attribute?

I haven't added it.  If I needed to, it would be:

        def getSide(self): return self.width)
        side = property(getSide)

in the body of ImmutableSquare, right after the def
for __init__.  This seems smoothest.

The alternative approach is perhaps more interesting:

class ImmutableSquare(ImmutableRectangle):
    def __init__(self, side):
        object.__setattr__(self, 'side', side)
    def getSide(self): return self.side
    width = property(getSide)
    heigth = property(getSide)

This 'transparently, retroactively and noninvasively' turns
all of ImmutableRectangle's methods that access self.width
and self.heigth into 'Template Methods' (in the Gof4 DP
sense).  I think it's cool and of course pre-emptively answers
objections from misguided souls about 'but ImmutableSquare
should hold only one reference to its side, not two'.  But it
will make no measurable difference (if ImmutableRectangle
has done serious memory optimization by defining __slots__,
there are two per-instance references willy nilly, and all that
ImmutableSquare should do should be to define its own empy
__slots__ to avoid wasting yet more memory:-), and I think
the 'coolness factor' plays both way -- the first solution is
trivially obvious, the second one is 'clever', so the first one is
more immediately understandable and therefore, I think, it IS
the preferable one in this simple case.

The 'trick' of the "noninvasive TemplateMethod'ing" (turning
'actual' attributes that a base class references on self, into
properties in a derived class, so one can compute them on
the fly) may be worth keeping in mind for possible future needs
where it might offer the best approach, though.  It's not all
THAT tricky, after all -- just enough to make a plainer idea
preferable when one offers itself as evident:-).


Alex




More information about the Python-list mailing list