More decisions.
This commit is contained in:
parent
66d4f339be
commit
3ff288b8ae
203
pep-3119.txt
203
pep-3119.txt
|
@ -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
|
||||
==========
|
||||
|
|
Loading…
Reference in New Issue