[Python-3000] Need help completing ABC pep

Guido van Rossum guido at python.org
Thu Apr 26 00:27:48 CEST 2007

(Forgot to answer this promptly.)

On 4/21/07, Jim Jewett <jimjjewett at gmail.com> wrote:
[PEP 3119]
> > > * "Should we also implement the issubset and issuperset methods found
> > > on the set type in Python 2? As these are just aliases for __le__ and
> > > __ge__, I'm tempted to leave these out."
> > > Leave them out.  Not terribly needed plus it is better to start out
> > > small.  They can easily be added later if called for.
> I think the names are more sensible than repurposing the numeric
> operators.  The "concrete" implementation can just forward to other
> name, so it doesn't cost much.

But the numeric operators are what everybody uses. So it makes more
sense to define these, and only these. It probably isn't even
necessary to implement the 'r' variants (__ror__ etc.) since these
only work if the other argument is also a Set.

> > I doubt that 'set' will be inherited from much (except for trivial
> > stuff) but returning a 'set' does make some sense. Although for
> > trivial subclasses (e.g. adding a different repr or a brand new
> > method) you'd like the results also to be an instance of the subclass.
> > If we could find a way to do that it would be best.
> You could use a variant of the numeric operator resolution.
> The left class wins, unless the right class is a subclass of the left.
> If this class does not have a constructor that accepts an iterable,
> (maybe fall back to the other class, then) fall back to a builtin set.

The problem isn't which side wins. The problem is what API to use to
create a new set. Since this is an *abstract* class, it's wrong to
just calling self.__class__() and assume its constructor takes an
iterable of values.

> In the Hashable section:
> > Another constraint is that hashable objects, once created,
> > should never change their value (as compared by ==) or their hash
> > value. If a class cannot guarantee this, it should not derive from
> > Hashable; if it cannot guarantee this for certain instances only,
> > __hash__ for those instances should raise a TypeError exception.
> Why not just return -1 (unless/until the value is stable)?  Is the -1
> special case being phased out too?

I don't recall that -1 was ever a special case at the Python level;
that was only done at the C level to make error checking easier.
Returning any hash value at all implies a guarantee that the object
value won't ever change (not just the hash value!); if you can't
guarantee that (e.g. for hash(([], []))) then you shouldn't return a
hash value. I don't think that hashing all objects with an unstable
value together on -1 supports a valid use case.

> ...
> I would say that Searchable might be worth separating into a Container
> subclass, but don't worry about the speed differences.  Many
> containers are small enough that constant effects are more important
> than big-O.  When big-O does matter, then the user may well want to
> distinguish between the O(1) and O(log N) case.  I think this gets
> detailed enough that it isn't worth putting in the common library.

Right. What is your specific proposal here? Adding
Searchable(Container) with the implication that __contains__ takes a
sequence as well as a single value? How should the type of the
argument be described? Should it be a Sequence? a Searchable?
something that is an instance of self.__class__?

> Why must a HashableSet or MutableSet be composable?  If this is
> because you figure any useful set has those properties (and I don't
> think so, when doing uniquification), then Set and ComposableSet
> should become BasicSet and Set?

Hmm, good point! This is in fact listed as an open issue for
HashableSet. If we can find a good use case for non-composable sets
that should nevertheless be hashable, we may end up with four classes:
set, composable set, hashable set, composable hashable set. (I think
you're hinting at an example; can you work it out a bit more?) For
mutable sets I think the case is weaker; these already support
in-place operations (|= etc.) which can easily and (usually
efficiently) be implemented using the primitives add() and discard(),
and it would be somewhat weird to have |= without |.

> ...
> Note that in the current sandbox  sandbox (which doesn't have
> *Ordered), the name BasicSet is used for a Set which isn't Sized.
> (Except that Set doesn't actually inherit from BasicSet, as I assume
> it should do.)

The sandbox/abc/abc.py code is way out of date. I'll try to update it.

> Continuing with the current sandbox
> Why must @abstractmethod come last, when mixed with other decorators?

Because it sets a function attribute. It is conceivable that other
decorators would make funtion attributes readonly. However the example
given is currently wrong -- @classmethod doesn't pass on function
attributes at all!

> IterableMapping needs to override __iter__; as written, it returns the
> empty iterator.

No, it is still an abstract method.

> Should Sequence.index take optional start and stop arguments?
>     def index(self, value, start=0, stop=None):
>         if stop is None:
>             stop = len(self)
>         for i, elem in enumerate(self):
>             if i < start:
>                 continue
>             if stop < i:
>                 break
>             if elem == value:
>                 return i
>         raise ValueError

Good question. I'm tempted to say no, and consider that a
list-specific extension.

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

More information about the Python-3000 mailing list