Deal with some open issues. Add some others. Will be posting soon.

This commit is contained in:
Guido van Rossum 2007-04-26 18:24:07 +00:00
parent fc624d8d81
commit ac9a2701b5
1 changed files with 120 additions and 67 deletions

View File

@ -7,7 +7,7 @@ Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 18-Apr-2007
Post-History: Not yet posted
Post-History: 26-Apr-2007
Abstract
@ -213,19 +213,18 @@ These ABCs are closer to ``object`` in the ABC hierarchy.
``PartiallyOrdered``
This ABC defines the 4 inequality operations ``<``, ``<=``, ``>=``,
``>``. (Note that ``==`` and ``!=`` are defined by ``object``.)
Classes deriving from this ABC should satisfy weak invariants such
as ``a < b < c`` implies ``a < c`` but don't require that for any
two instances ``x`` and ``y`` exactly one of ``x < y``, ``x == y``
or ``x >= y`` apply.
Classes deriving from this ABC should implement a partial order
as defined in mathematics. [9]_
``TotallyOrdered``
This ABC derives from ``PartiallyOrdered``. It adds no new
operations but implies a promise of stronger invariants. **Open
issues:** Should ``float`` derive from ``TotallyOrdered`` even
though for ``NaN`` this isn't strictly correct?
operations but implies a promise of stronger invariants.
Classes deriving from this ABC should implement a total order
as defined in mathematics. [10]_
**Open issues:** Where should these live? The ``collections`` module
doesn't seem right.
doesn't seem right, but making them built-ins seems a slippery slope
too.
One Trick Ponies
@ -252,7 +251,7 @@ These abstract classes represent single methods like ``__iter__`` or
instances only, ``__hash__`` for those instances should raise a
``TypeError`` exception.
Note: being an instance of this class does not imply that an
**Note:** being an instance of this class does not imply that an
object is immutable; e.g. a tuple containing a list as a member is
not immutable; its ``__hash__`` method raises ``TypeError``.
@ -266,7 +265,7 @@ These abstract classes represent single methods like ``__iter__`` or
The base class for classes defining ``__next__``. This derives
from ``Iterable``. The abstract ``__next__`` method raises
``StopIteration``. The concrete ``__iter__`` method returns
``self``. (Note: this assumes PEP 3114 is implemented.)
``self``.
``Sized``
The base class for classes defining ``__len__``. The ``__len__``
@ -274,13 +273,7 @@ These abstract classes represent single methods like ``__iter__`` or
The abstract ``__len__`` method returns 0. **Invariant:** If a
class ``C`` derives from ``Sized`` as well as from ``Iterable``,
the invariant ``sum(1 for x in o) == len(o)`` should hold for any
instance ``o`` of ``C``. **Open issues:** Is ``Sized`` the best
name? Proposed alternatives already tentatively rejected:
``Finite`` (nobody understood it), ``Lengthy``, ``Sizeable`` (both
too cute), ``Countable`` (the set of natural numbers is a
countable set in math), ``Enumerable`` (sounds like a sysnonym for
``Iterable``), ``Dimension``, ``Extent`` (sound like numbers to
me), ``Bounded`` (probably just as confusing as ``Fininte``).
instance ``o`` of ``C``.
``Container``
The base class for classes defining ``__contains__``. The
@ -290,7 +283,7 @@ These abstract classes represent single methods like ``__iter__`` or
``Iterable``, then ``(x in o for x in o)`` should be a generator
yielding only True values for any instance ``o`` of ``C``.
Note: strictly speaking, there are three variants of this method's
**Note:** strictly speaking, there are three variants of this method's
semantics. The first one is for sets and mappings, which is fast:
O(1) or O(log N). The second one is for membership checking on
sequences, which is slow: O(N). The third one is for subsequence
@ -337,25 +330,31 @@ out of the scope of a pragmatic proposal like this.
a set though! Sets have the additional invariant that each
element occurs only once (as can be determined by iteration), and
in addition sets define concrete operators that implement the
inequality operations as subclass/superclass tests.
inequality operations as subclass/superclass tests. In general,
the invariants for finite sets in mathematics hold. [11]_
Sets with different implementations can be compared safely,
efficiently and correctly. Because ``Set`` derives from
``Sized``, ``__eq__`` takes a shortcut and returns ``False``
immediately if two sets of unequal length are compared.
Similarly, ``__le__`` returns ``False`` immediately if the first
set has more members than the second set. Note that set inclusion
implements only a partial ordering; e.g. ``{1, 2}`` and ``{1, 3}``
are not ordered (all three of ``<``, ``==`` and ``>`` return
``False`` for these arguments). Sets cannot be ordered relative
to mappings or sequences, but they can be compared for equality
(and then they always compare unequal).
(usually) efficiently and correctly using the mathematical
definitions of the subclass/superclass operations for finite sets.
The ordering operations have concrete implementations; subclasses
may override these for speed but should maintain the semantics.
Because ``Set`` derives from ``Sized``, ``__eq__`` may take a
shortcut and returns ``False`` immediately if two sets of unequal
length are compared. Similarly, ``__le__`` may return ``False``
immediately if the first set has more members than the second set.
Note that set inclusion implements only a partial ordering;
e.g. ``{1, 2}`` and ``{1, 3}`` are not ordered (all three of
``<``, ``==`` and ``>`` return ``False`` for these arguments).
Sets cannot be ordered relative to mappings or sequences, but they
can be compared to those for equality (and then they always
compare unequal).
Note: the ``issubset`` and ``issuperset`` methods found on the set
type in Python 2 are not supported, as these are mostly just
**Note:** the ``issubset`` and ``issuperset`` methods found on the
set type in Python 2 are not supported, as these are mostly just
aliases for ``__le__`` and ``__ge__``.
**Open issues:** Spell out the invariants and method definitions.
**Open issues:** should we define comparison of instances of
different concrete set types this way?
``ComposableSet``
This is a subclass of ``Set`` that defines abstract operators to
@ -366,14 +365,22 @@ out of the scope of a pragmatic proposal like this.
``NotImplementedError``; this is because any generic
implementation would have to create new instances but the ABCs
don't (and shouldn't, IMO) provide an API for creating new
instances. **Invariants:** The implementations of these operators
should ensure that the results match the mathematical definition
of set composition.
instances. The implementations of these operators should ensure
that the results match the mathematical definition of set
composition. [11]_
**Open issues:** Should I spell out the invariants? Should we
define an API for creating new instances (e.g. a class method or a
fixed constructor signature)? Should we just pick a concrete
return type (e.g. ``set``)?
**Open issues:** Should ``__or__`` and friends be abstract or
concrete methods? Making them abstract means that every
ComposableSet implementation must reimplement all of them. But
making them concrete begs the question of the actual return type:
since the ABC doesn't (and IMO shouldn't) define the constructor
signature for subclasses, the concrete implementations in the ABC
don't have an API to construct a new instance given an iterable.
Perhaps the right choice is to have a static concrete factory
function ``fromiterable`` which takes an iterable and returns
a ``ComposableSet`` instance. Subclasses can override this and
benefit from the default implementations of ``__or__`` etc.; or
they can override ``__or__`` if they want to.
``HashableSet``
This is a subclass of both ``ComposableSet`` and ``Hashable``. It
@ -385,8 +392,8 @@ out of the scope of a pragmatic proposal like this.
values for different types of numbers and strings.)
**Open issues:** Spell out the hash algorithm. Should there be
another ABC that derives from Set and Hashable (but not from
Composable)?
another ABC that derives from Set and Hashable, but not from
Composable?
``MutableSet``
This is a subclass of ``ComposableSet`` implementing additional
@ -421,7 +428,7 @@ out of the scope of a pragmatic proposal like this.
``.clear()``
Concrete method that empties the set. The default
implementation repeatedly calls ``self.pop()`` until
``KeyError`` is caught. (Note: this is probably much slower
``KeyError`` is caught. (**Note:** this is likely much slower
than simply creating a new set, even if an implementation
overrides it with a faster approach; but in some cases object
identity is important.)
@ -467,21 +474,52 @@ The built-in type ``dict`` derives from ``MutableMapping``.
raise ``KeyError``, and ``False`` if it does.
``Mapping``
A subclass of ``BasicMapping``, ``iterable`` and ``Sized``. It
defines concrete methods ``__eq__``, ``keys``, ``items``,
``values``. Iterating over a mapping should return all the valid
keys (i.e. those keys for which ``.__getitem__()`` returns a
value), once each, and nothing else. The lengh of a mapping
should equal to the number of elements returned by iterating over
the object until the end of the iterator is reached (this is
implied by the invariant listed above for ``Sized``). Two
mappings, even with different implementations, can be compared for
equality, and are considered equal if and only iff their items
compare equal when converted to sets. The ``keys``, ``items`` and
``values`` methods return views; ``keys`` and ``items`` return
``Set`` views, ``values`` returns a ``Container`` view. The
following invariant should hold: m.items() == set(zip(m.keys(),
m.values())).
A subclass of ``BasicMapping``, ``Iterable`` and ``Sized``. The
keys of a mapping naturally form a set. The (key, value) pairs
are also referred to as items. The items also form a set.
Methods:
``__len__``
Abstract method returning the length of the key set.
``__iter__``
Abstract method returning each key in the key set exactly once.
``__eq__``
Concrete method for comparing mappings. Two mappings, even
with different implementations, can be compared for equality,
and are considered equal if and only iff their item sets are
equal. **Open issues:** should we define comparison of
instances of different concrete mapping types this way?
``keys``
Concrete method returning the key set as a ``Set``. The
default concrete implementation returns a "view" on the key
set (meaning if the underlying mapping is modified, the view's
value changes correspondingly); subclasses are not required to
return a view but they should return a ``Set``.
``items``
Concrete method returning the items as a ``Set``. The default
concrete implementation returns a "view" on the item set;
subclasses are not required to return a view but they should
return a ``Set``.
``values``
Concrete method returning the values as a sized, iterable
container (not a set!). The default concrete implementation
returns a "view" on the values of the mapping; subclasses are
not required to return a view but they should return a sized,
iterable container.
The following invariant should hold for any mapping ``m``::
set(m.items()) == set(zip(m.keys(), m.values()))
i.e. iterating over the keys and the values in parallel should
return *corresponding* keys and values. **Open issues:** Should
this always be required? How about the stronger invariant using
``list()`` instead of ``set()``?
``HashableMapping``
A subclass of ``Mapping`` and ``Hashable``. The values should be
@ -492,11 +530,8 @@ The built-in type ``dict`` derives from ``MutableMapping``.
A subclass of ``Mapping`` that also implements some standard
mutating methods. Abstract methods include ``__setitem__``,
``__delitem__``. Concrete methods include ``pop``, ``popitem``,
``clear``, ``update``. Note: ``setdefault`` is *not* included.
**Open issues:**
* We should say more about mapping view types.
``clear``, ``update``. **Note:** ``setdefault`` is *not* included.
**Open issues:** Write out the specs for the methods.
Sequences
@ -510,7 +545,7 @@ from ``HashableSequence``.
``Sequence``
A subclass of ``Iterable``, ``Sized``, ``Container``. It
defines a new abstract method ``__getitem__`` that has a
defines a new abstract method ``__getitem__`` that has a somewhat
complicated signature: when called with an integer, it returns an
element of the sequence or raises ``IndexError``; when called with
a ``slice`` object, it returns another ``Sequence``. The concrete
@ -535,10 +570,19 @@ from ``HashableSequence``.
well as slices), ``__delitem__`` (ditto), ``insert``, ``append``,
``reverse``. Concrete mutating methods: ``extend``, ``pop``,
``remove``. Concrete mutating operators: ``+=``, ``*=`` (these
mutate the object in place). Note: this does not define
mutate the object in place). **Note:** this does not define
``sort()`` -- that is only required to exist on genuine ``list``
instances.
**Open issues:** If all the elements of a sequence are totally
ordered, the sequence itself can be totally ordered with respect to
other sequences containing corresponding items of the same type.
Should we reflect this by making ``Sequence`` derive from
``TotallyOrdered``? Or ``Partiallyordered``? Also, we could easily
define comparison of sequences of different types, so that e.g.
``(1, 2, 3) == [1, 2, 3]`` and ``(1, 2) < [1, 2, 3]``. Should we?
(It might imply ``["a", "b"] == "ab"`` and ``[1, 2] == b"\1\2"``.)
Strings
-------
@ -686,10 +730,19 @@ References
.. [7] Unifying types and classes in Python 2.2, by GvR
(http://www.python.org/download/releases/2.2.3/descrintro/)
.. [8] "Putting Metaclasses to Work: A New Dimension in Object-Oriented
Programming", by Ira R. Forman and Scott H. Danforth
.. [8] Putting Metaclasses to Work: A New Dimension in Object-Oriented
Programming, by Ira R. Forman and Scott H. Danforth
(http://www.amazon.com/gp/product/0201433052)
.. [9] Partial order, in Wikipedia
(http://en.wikipedia.org/wiki/Partial_order)
.. [10] Total order, in Wikipedia
(http://en.wikipedia.org/wiki/Total_order)
.. [11] Finite set, in Wikipedia
(http://en.wikipedia.org/wiki/Finite_set)
Copyright
=========