Case study: library class inheritance with property declarations

cdleary at gmail.com cdleary at gmail.com
Thu Aug 2 09:49:42 EDT 2007


Hi all,

It's possible that I'm missing the obvious -- I've been up for over 24
hours and I'm most likely dehydrated from mass coffee intake, but I
figure many people in similar circumstances will be searching
comp.lang.python one day, so here goes!


class LibraryClass(object):

    """
    A class whose implementation is out of my hands.
    """

    def __init__(self):
        """
        Follows good dynamic-language form and binds all instance
        variables at initialization time.
        """
        # Omitted: complex initialization functionality.
        self.useful_attr = None


class MyInheritedClass(LibraryClass):

    """
    My refinement of the functionality offered by the LibraryClass. I
    now want the instance to initialize with a reference to an
external
    object, and the useful_attr defined in the superclass will now
    reference an attribute of that external object via fget.

    Changing the attribute of the external object has undefined
    behavior, so I want to omit an fset in the property declaration;
    however, I have to provide some way for the superclass to
    initialize useful_attr -- I can't change the superclass' code, as
it
    resides in a library that is out of my hands.
    """

    def __init__(self, external_obj):
        LibraryClass.__init__(self)
        self._external_obj = external_obj

    def get_useful_attr(self):
        return self._external_obj.proxy_useful_attr

    useful_attr = property(fget=get_useful_attr)


def test():
    class _Fake(object):
        pass
    external_obj = _Fake()
    external_obj.proxy_useful_attr = 12
    spam = MyInheritedClass(external_obj)


if __name__ == '__main__':
    test()
EOF


If you're one of those people who doesn't like laboriously reading
contrived examples (elitists ;) I'll boil it down for you: Library
class initializes some attribute, but derived class wants to eliminate
fsets for said attribute. As a result, our ideal solution

Of course, this means that the derived class will raise an error in
some circumstances where the base class wouldn't (when you're setting
that attribute), but one can assume that the inheritance is
worthwhile.

How do I come up with silly solutions to circumvent this? Let me count
the ways...

1. So-and-so: make an fset that does nothing. This ignores (what
should be) errors in code that uses MyInheritedClass in an attempt to
accommodate a useless statement in the base class -- surely non-ideal.
2. The ugly one: since you can probably view the library, copy and
paste the complex initialization functionality in the above, but leave
out the bad statement. This not only forfeits the ideals of
inheritance, but makes you totally incompatible with future library
changes.
3. Cheerleader: Pure evil. On top of the ugliness of 2, you assume
that across library revisions the indenting won't change and that the
troublesome statement will remain on the same line, and pull off one
of these babies:

def super_evil_test():
    from inspect import getsourcelines
    exec(''.join([line[4:] for line in
                  getsourcelines(LibraryClass.__init__)[0][:-1]]))
    LibraryClass.__init__ = __init__
    test() # Passes, but several angels no longer get their wings

Totally kidding, everybody! I hope Guido doesn't read this thread...

And this concludes the sleep deprived rambling that follows the
somewhat interesting case in point. Thoughts?




More information about the Python-list mailing list