How about "pure virtual methods"?

Noam Raphael 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,
Noam



More information about the Python-list mailing list