[Python-talk] Un-inheriting
Kent Johnson
kent37 at tds.net
Sat Mar 31 08:43:00 EDT 2007
Bill Freeman wrote:
> Suppose that you have a base class foo providing a bunch of stuff
> (methods, constants, (intended to be) constant dictionaries, etc.: A,
> B, C, D, E, F, G, H...
>
> You have a class bar that needs to implement 80% of that
> functionality, so it makes sense to derive from foo. Bar overrides,
> say, 15% of the other features, and implements a bunch of new stuff:
> W, X, Y, Z. Still a great case for inheritance.
>
> But bar doesn't need member function A. In fact, bar should not have
> A. Since A is a method, a practical solution is to implement an A in
> bar that simply raises a suitable AttributeError ("bar instance has no
> attribute 'A'").
>
> But this is unsatisfactory under introspection. Further, if what you
> wanted to hide is not a method, it doesn't work at all.
>
> There is renaming foo to fooBase, foo from that, where the
> implementation of A is moved to foo, and bar inherits from fooBase.
> Python's multiple inheritance capabilities makes this feasible, even
> with more complex structures (bar is a foo without an A, ugh is a foo
> without a B, bletch is a foo without a C,...). I'm not sure that this
> makes for the most readable code in all cases.
This sounds like a reasonable solution. Having bar inherit from foo is
bad design, because "bar is-a foo" is not true.
>
> One could, I suppose, override __getattr__() and __setattr__() to
> suppress A, but won't that affects performance on all attribute
> accesses?
This won't work. __getatttr__() is only called when normal attribute
lookup fails. With new-style classes you can override __getattribute__()
to do what you want.
It sounds like you are using inheritance purely for code sharing, not
for any value as a conceptual model. You might consider alternatives.
You could define mixin classes with subsets of the functions you need.
This is just a different way to think about the multiple-inheritance
solution. You could have classes ImplementsA, ImplementsBCDEFGH,
ImplementsWXYZ, and
class foo(ImplementsA, ImplementsBCDEFGH)
class bar(ImplementsBCDEFGH, ImplementsWXYZ)
etc...hopefully with better names than this.
Do the different methods need access to the instance data or could they
be written as standalone functions? Perhaps you could put ABCD... into
one or more utility classes as standalone functions and manually
delegate to them. Or you could put them into helper classes and
automatically delegate to them using __getattr__(). (Yes, this will have
an impact on performance. I don't know how much. My guess is it would
not be more than the cost of a few function calls. Is this code
time-critical or are you making up a performance requirement?)
>
> bar could define A with:
> A=property()
> This makes A return an attribute error for any kind of vanilla access.
> It doesn't work for classic classes (according to the documents), and
> I was hoping to get away with classic classes to maximize the number
> of places where this code would just work, but that's probably being
> overly fussy.
Properties don't work with classic classes. They give the appearance of
working in some situations. Don't be fooled! They don't work.
Kent
More information about the Python-talk
mailing list