How about "pure virtual methods"?
noamr at remove.the.dot.myrea.lbox.com
Wed Dec 22 00:55:16 CET 2004
Thank you all, especially Alex for your enlightening discussion, and
Scott for your implementation. I'm sorry that I can't be involved in a
daily manner - but I did read all of the posts in this thread. They
helped me understand the situation better, and convinced me that indeed
this feature is needed. Let's see if I can convince you too.
First, the actual situation in which I stood, which made me think, "I
would like to declare a method as not implemented, so that subclasses
would have to implement it."
I wrote a system in which objects had to interact between themselves. In
my design, all those objects had to implement a few methods for the
interaction to work. So I wrote a base class for all those objects, with
a few methods which the subclasses had to implement. I think it's good,
for *me*, to have an explicit list of what should be implemented, so
that when (in a function) I expect to get an object of this kind I know
what I may and may not do with it.
Then, I wrote the classes themselves. And I wrote unit tests for them.
(Ok, I lie. I didn't. But I should have!) Afterwards, I decided that I
needed all my objects of that kind to supply another method. So I added
another "raise NotImplementedError" method to the base class. But what
about the unit tests? They would have still reported a success - where
of course they shouldn't have; my classes, in this stage, didn't do what
they were expected to do. This problem might arise even when not
changing the interface at all - it's quite easy to write a class which,
by mistake, doesn't implement all the interface. Its successful unit
tests may check every single line of code of that class, but a complete
method was simply forgotten, and you wouldn't notice it until you try
the class in the larger framework (and, as I understand, the point of
unit testing is to test the class on its own, before integrating it).
Ok. This was the practical reason why this is needed. Please note that I
didn't use "isinstance" even once - all my functions used the
*interface* of the objects they got. I needed the extra checking for
myself - if someone wanted to implement a class that wouldn't inherit
from my base class, but would nevertheless implement the required
interface, he was free to do it, and it would have worked fine with the
framework I wrote.
Now for the "theoretical" reason why this is needed. My reasoning is
based on the existence of "isinstance" in Python. Well, what is the
purpose of isinstance? I claim that it doesn't test if an object *is* of
a given type. If that would have been its purpose, it would have checked
whether type(obj) == something. Rather, it checks whether an object is a
subclass of a given type. Why should we want such a function? A subclass
may do a completely different thing from what the original class did!
The answer is that a subclass is guaranteed to have the same *interface*
as the base class. And that's what matters.
So I conclude that a subclass, in Python, must implement the interface
of its parent class. Usually, this is obvious - there's no way for a
subclass not to implement the interface of its parent class, simply
because it can only override methods, but can't remove methods. But what
shall we do if the some methods in the base class consist *only* of an
interface? Can we implement only a part of the interface, and claim that
instances of that class are instances of the original class, in the
"isinstance" fashion? My answer is no. The whole point of "isinstance"
is to check whether an instance implements an interface. If it doesn't -
what is the meaning of the True that isinstance returns? So we should
simply not allow instances of such classes.
You might say that abstract classes at the base of the hierarchy are
"not Pythonic". But they are in Python already - the class basestring is
exactly that. It is an uninstantiable class, which is there only so that
you would be able to do isinstance(x, basestring). Classes with
"notimplemented" methods would behave in exactly the same way - you
wouldn't be able to instantiate them, just to subclass them (and to
check, using isinstance, whether they implement the required protocol,
which I agree that wouldn't be Pythonic, probably).
Ok. This is why I think this feature fits Python like a glove to a hand.
Please post your comments on this! I apologize now - I may not be able
to reply in the next few days. But I will read them at the end, and I
will try to answer.
Have a good day,
More information about the Python-list