More decisions.

This commit is contained in:
Guido van Rossum 2007-04-20 23:06:41 +00:00
parent 66d4f339be
commit 3ff288b8ae
1 changed files with 89 additions and 114 deletions

View File

@ -13,8 +13,6 @@ Post-History: Not yet posted
Abstract
========
**THIS IS A WORK IN PROGRESS! DON'T REVIEW YET!**
This is a proposal to add Abstract Base Class (ABC) support to Python
3000. It proposes:
@ -25,11 +23,6 @@ This is a proposal to add Abstract Base Class (ABC) support to Python
* Specific ABCs for containers and iterators, to be added to the
collections module.
* Specific ABCs for numbers, to be added to a new module, yet to be
named.
* Guidelines for writing additional ABCs.
Much of the thinking that went into the proposal is not about the
specific mechanism of ABCs, as contrasted with Interfaces or Generic
Functions (GFs), but about clarifying philosophical issues like "what
@ -40,8 +33,8 @@ Acknowledgements
----------------
Talin wrote the Rationale below [1]_ as well as most of the section on
ABCs vs. Interfaces. For that alone he deserves co-authorship. But
the rest of the PEP uses "I" referring to the first author.
ABCs vs. Interfaces. For that alone he deserves co-authorship. The
rest of the PEP uses "I" referring to the first author.
Rationale
@ -120,23 +113,16 @@ The specification follows the four categories listed in the abstract:
* An "ABC support framework" which defines a metaclass, a base class,
a decorator, and some helpers that make it easy to define ABCs.
This will be added as a new library module named "abc", or
(probably) made built-in functionality.
* Specific ABCs for containers and iterators, to be added to the
collections module.
* Specific ABCs for numbers, to be added to a new module that is yet
to be named.
* Guidelines for writing additional ABCs.
ABC Support Framework
---------------------
The abc module will define some utilities that help defining ABCs.
These are:
We define the following four new built-in objects that help defining
ABCs:
``@abstractmethod``
A decorator used to declare abstract methods. This should only be
@ -146,46 +132,54 @@ These are:
Such a methods may be called from the overriding method in the
subclass (using ``super`` or direct invocation).
``Abstract``
A class implementing the constraint that it or its subclasses
cannot be instantiated unless each abstract method has been
overridden. Its metaclass is ``AbstractClass``. Note: being
derived from ``Abstract`` does not make a class abstract; the
abstract-ness is decided on a per-class basis, depending on
whether all methods defined with ``@abstractmethod`` have been
overridden.
``AbstractClass``
The metaclass of Abstract (and all classes derived from it). Its
purpose is to collect the information during the class
construction stage. It derives from ``type``.
A metaclass to be used with classes containing abstract methods.
Classes whose metaclass is (or derives from) ``AbstractClass``
cannot be instantiated unless all methods declared abstract using
the ``@abstractmethod`` decorator have been overridden by concrete
methods.
``Abstract``
An empty helper class whose metaclass is ``AbstractClass``. This
only exists as a minor convenience; deriving a class from
``Abstract`` is the same as setting its metaclass to
``AbstractClass``.
``AbstractInstantiationError``
The exception raised when attempting to instantiate an abstract
class. It derives from ``TypeError``.
A possible implementation would add an attribute
``__abstractmethod__`` to any method declared with
``@abstractmethod``, and add the names of all such abstract methods to
a class attribute named ``__abstractmethods__``. Then the
``Abstract.__new__()`` method would raise an exception if any abstract
methods exist on the class being instantiated. For details see [2]_.
(However, this would incur a significant cost upon each instantiation.
A better approach would be to do most of the work in the metaclass.)
**Open issues:**
**Open issue:** Probably ``abstractmethod`` and
``AbstractInstantiationError`` should become built-ins, ``Abstract``'s
functionality should be subsumed by ``object``, and
``AbstractClass``'s functionality should be merged into ``type``.
This would require a more efficient implementation of the
instantiable-test sketched above.
* Implementing the prohibition on instantiation may weigh down
instance creation of popular built-in classes like ``tuple`` or
``str``. Perhaps concrete built-in classes can use a shortcut; or
perhaps there's a more efficient implementation.
* Do we even need ``Abstract`` and ``AbstractClass``? Their
functionality can be subsumed into ``object`` and ``type``,
respectively.
* Even if we keep them separate, ``Abstract`` is quite unnecessary
since there is hardly any difference in complexity between this::
class C(metaclass=AbstractClass):
@abstractmethod
def foo(self): ...
and this::
class C(Abstract):
@abstractmethod
def foo(self): ...
ABCs for Containers and Iterators
---------------------------------
The collections module will define ABCs necessary and sufficient to
work with sets, mappings, sequences, and some helper types such as
The ``collections`` module will define ABCs necessary and sufficient
to work with sets, mappings, sequences, and some helper types such as
iterators and dictionary views.
The ABCs provide implementations of their abstract methods that are
@ -200,7 +194,33 @@ itself, fulfilling an important invariant of iterators (which in
Python 2 has to be implemented anew by each iterator class).
No ABCs override ``__init__``, ``__new__``, ``__str__`` or
``__repr__``.
``__repr__``. Defining a standard constructor signature would
unnecessarily constrain custom container types, for example Patricia
trees or gdbm files. Defining a specific string representation for a
collection is similarly left up to individual implementations.
Ordering ABCs
'''''''''''''
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.
``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?
**Open issues:** Where should these live? The ``collections`` module
doesn't seem right.
One Trick Ponies
@ -278,21 +298,6 @@ These abstract classes represent single methods like ``__iter__`` or
never yielded by ``iter(o)``. A suggested name for the third form
is ``Searchable``.
``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.
``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?
Sets
''''
@ -321,7 +326,6 @@ general without using a symbolic algebra package. So I consider this
out of the scope of a pragmatic proposal like this.
``Set``
This is a finite, iterable, partially ordered container, i.e. a
subclass of ``Sized``, ``Iterable``, ``Container`` and
``PartiallyOrdered``. Not every subset of those three classes is
@ -364,7 +368,7 @@ out of the scope of a pragmatic proposal like this.
**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``)? Should we add the ``copy`` method?
return type (e.g. ``set``)?
``HashableSet``
This is a subclass of both ``ComposableSet`` and ``Hashable``. It
@ -444,26 +448,22 @@ The built-in type ``dict`` derives from ``MutableMapping``.
Concrete method returning ``True`` if ``self[key]`` does not
raise ``KeyError``, and ``False`` if it does.
``IterableMapping``
A subclass of ``BasicMapping`` and ``Iterable``. It defines no
new methods. Iterating over such an object should return all the
valid keys (i.e. those keys for which ``.__getitem__()`` returns a
value), once each, and nothing else. It is possible that the
iteration never ends.
``Mapping``
A subclass of ``IterableMapping`` and ``Sized``. It defines
concrete methods ``__eq__``, ``keys``, ``items``, ``values``. The
lengh of such an object should equal to the number of elements
returned by iterating over the object until the end of the
iterator is reached. 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``. 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())).
``HashableMapping``
A subclass of ``Mapping`` and ``Hashable``. The values should be
@ -478,13 +478,12 @@ The built-in type ``dict`` derives from ``MutableMapping``.
**Open issues:**
* Do we need BasicMapping and IterableMapping? We should probably
just start with Mapping.
* Do we need both ``BasicMapping`` and ``Mapping``? We could just
start with ``Mapping``; but I believe there's some use for a
non-iterable mapping that nevertheless behaves like a basic mapping.
* We should say more about mapping view types.
* Should we add the ``copy`` method?
Sequences
'''''''''
@ -553,15 +552,15 @@ PEP.
Guidelines for Writing ABCs
---------------------------
Some sugegstions:
Some suggestions:
* Use @abstractmethod and Abstract base class.
* Use ``@abstractmethod`` and the ``Abstract`` base class.
* Define abstract methods that could be useful as an end point when
called via a super chain.
* Define concrete methods that are very simple permutations of
abstract methods (e.g. Mapping.get).
abstract methods (e.g. ``Mapping.get``).
* Keep abstract classes small, one per use case instead of one per
concept.
@ -652,30 +651,6 @@ simplest case, one can define a "category membership" generic function
that simply returns False in the base implementation, and then provide
overrides that return True for any classes of interest.
Open Issues
===========
Apart from the open issues already sprinkled through the text above,
and the "category one" issue of deciding between ABCs, GFs and
Interfaces there are some fairly large looming issues.
* Should we strive to use ABCs for *all* areas of Python? The wiki
page for ABCs created by Bill Janssen [3]_ tries to be
comprehensive: it defines everything from Comparable and Object to
files. The current PEP tries to limit itself to three areas: ABC
support (like the ``@abstractmethod`` decorator), collections types,
and numbers. The proposed class hierarchy for new I/O described in
PEP 3116 already including de-facto ABCs; these can easily be
upgraded to use the mechanisms from the current PEP if it is
accepted. Perhaps Orderable would be a good concept to define
in the current PEP; I don't expect we need to go further.
* Perhaps the numeric classes could be moved to a separate PEP; the
issues there don't have much in common with the issues for
collection types.
* What else?
References
==========