[Python-3000] Generic function PEP won't make it in time (original) (raw)

Guido van Rossum guido at python.org
Tue Apr 24 01:49:52 CEST 2007


On 4/23/07, Phillip J. Eby <pje at telecommunity.com> wrote:

At 03:16 PM 4/23/2007 -0700, Guido van Rossum wrote: >On 4/23/07, Phillip J. Eby <pje at telecommunity.com> wrote: >>Assuming that: >> >>1. If you call such a function, it will raise some error, like >>NotImplementedError > >That would be up to the author of the function; they would have to >explicitly raise NotImplementedError in the body. The ABC proposal >allows meaningful abstract methods that can be called (only) via >"super"; the use case for this is that the abstract method might be >the one that decides which exception should be thrown (e.g. >getitem and next do this), or perhaps it could provide a >default implementation for certain types. (Potential example of the >latter: Sequence.getitem() could raise IndexError when the >argument is an Integer but handle the case where the argument is a >slice instance, assuming there's a suitable factory which could be a >designated class method.)

Ah... interesting. This is different from what I understood to be "abstract" methods in other languages where an abstract method is always one that does not have an actual implementation. I guess I skimmed PEP 3119 a little too quickly. It sounds like your proposal is to mark methods as "abstract" even if they have a useful "null" implementation.

Not exactly. Some of the proposed ABCs have concrete methods. These are the kinds you'd find in mixin classes for Python 2. (Example: Iterator.iter() is a concrete method returning self. You almost never have a need to override it.) The abstract ones have null implementations that aren't all that useful for two reasons: (a) they implement an utter edge case (e.g. an empty iterator) (b) they must be overridden. Their main purpose is to provide an example -- either they show which exception to raise (next, getitem) or they show the type of value to return (hash).

I guess I don't see what this adds, at least for the examples in the sandbox, except for making the class non-instantiable as a side-effect.

I guess I exaggerated the usefulness of the null implementations. It's perfectly fine not to call the null implementation but to inline it (e.g. raise StopIteration instead of return super(self).next()).

Of course, if @abstract were a class decorator as well as a function decorator, then it could have a single meaning in both contexts: "this thing shouldn't be callable".

That is to say, this: @abstract class Iterator(Iterable): ... would simply mean calling "Iterator()" would result in a NotImplementedError, just like marking a function @abstract means that calling it would result in a NotImplementedError.

Yeah, but it would be less specific because (in the case of ABCs that define multiple methods) it wouldn't tell you which mwethods you have to override.

And, as far as I can see, the only ABC method I'd mark @abstract individually would be Hashable.hash: everything else here looks to me like a perfectly valid "empty" implementation of the method(s) in question.

Actually, Hashable.hash is also perfectly valid. :-)

I suppose there is some value in requiring people to override @abstract methods to make a subclass instantiable, versus merely using the lack of an @abstract class decorator to indicate that a subclass is concrete. But I wonder if being able to have just one @abstract decorator (that always means "you can't call this by default") mightn't be worth giving up that tiny bit of extra type checking?

I prefer to follow the lead of C++ here -- an abstract class is abstract by virtue of having at least one abstract method.

That the abstract methods are still somewhat useful implementations is mostly to provide a valid (if not necessarily useful) end point for super-calling in cooperative MI schemes.

-- --Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-3000 mailing list