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 -- http://mail.python.org/mailman/listinfo/python-list