202 lines
7.2 KiB
Plaintext
202 lines
7.2 KiB
Plaintext
PEP: 3119
|
||
Title: Introducing Abstract Base Classes
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: Guido van Rossum <guido@python.org>, Talin
|
||
Status: Draft
|
||
Type: Standards Track
|
||
Content-Type: text/x-rst
|
||
Created: 18-Apr-2007
|
||
Post-History: 18-Apr-2007
|
||
|
||
|
||
Abstract
|
||
========
|
||
|
||
This is a proposal to add Abstract Base Class (ABC) support to Python
|
||
3000. It proposes:
|
||
|
||
* 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".
|
||
|
||
* 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.
|
||
|
||
|
||
Rationale
|
||
=========
|
||
|
||
In the domain of object-oriented programming, the usage patterns for
|
||
interacting with an object can be divided into two basic categories,
|
||
which are 'invocation' and 'inspection'.
|
||
|
||
Invocation means interacting with an object by invoking its methods.
|
||
Usually this is combined with polymorphism, so that invoking a given
|
||
method may run different code depending on the type of an object.
|
||
|
||
Inspection means the ability for external code (outside of the object's
|
||
methods) to examine the type or properties of that object, and make
|
||
decisions on how to treat that object based on that information.
|
||
|
||
Both usage patterns serve the same general end, which is to be able to
|
||
support the processing of diverse and potentially novel objects in a
|
||
uniform way, but at the same time allowing processing decisions to be
|
||
customized for each different type of object.
|
||
|
||
In classical OOP theory, invocation is the preferred usage pattern, and
|
||
inspection is actively discouraged, being considered a relic of an
|
||
earlier, procedural programming style. However, in practice this view is
|
||
simply too dogmatic and inflexible, and leads to a kind of design
|
||
rigidity that is very much at odds with the dynamic nature of a language
|
||
like Python.
|
||
|
||
In particular, there is often a need to process objects in a way that
|
||
wasn't anticipated by the creator of the object class. It is not always
|
||
the best solution to build in to every object methods that satisfy the
|
||
needs of every possible user of that object. Moreover, there are many
|
||
powerful dispatch philosophies that are in direct contrast to the
|
||
classic OOP requirement of behavior being strictly encapsulated within
|
||
an object, examples being rule or pattern-match driven logic.
|
||
|
||
On the the other hand, one of the criticisms of inspection by classic
|
||
OOP theorists is the lack of formalisms and the ad hoc nature of what is
|
||
being inspected. In a language such as Python, in which almost any
|
||
aspect of an object can be reflected and directly accessed by external
|
||
code, there are many different ways to test whether an object conforms
|
||
to a particular protocol or not. For example, if asking 'is this object
|
||
a mutable sequence container?', one can look for a base class of 'list',
|
||
or one can look for a method named '__getitem__'. But note that although
|
||
these tests may seem obvious, neither of them are correct, as one
|
||
generates false negatives, and the other false positives.
|
||
|
||
The generally agreed-upon remedy is to standardize the tests, and group
|
||
them into a formal arrangement. This is most easily done by associating
|
||
with each class a set of standard testable properties, either via the
|
||
inheritance mechanism or some other means. Each test carries with it a
|
||
set of promises: it contains a promise about the general behavior of the
|
||
class, and a promise as to what other class methods will be available.
|
||
|
||
This PEP proposes a particular strategy for organizing these tests known
|
||
as Abstract Base Classes, or ABC. ABCs are simply Python classes that
|
||
are added into an object's inheritance tree to signal certain features
|
||
of that object to an external inspector. Tests are done using
|
||
isinstance(), and the presence of a particular ABC means that the test
|
||
has passed.
|
||
|
||
Like all other things in Python, these promises are in the nature of a
|
||
gentlemen's agreement - which means that the language does not attempt
|
||
to enforce that these promises are kept.
|
||
|
||
|
||
Specification
|
||
=============
|
||
|
||
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".
|
||
|
||
* 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.
|
||
|
||
|
||
ABC Support Framework
|
||
---------------------
|
||
|
||
The abc module will define some utilities that help defining ABCs.
|
||
These are:
|
||
|
||
``@abstractmethod``
|
||
A decorator to be used to declare abstract methods. This should
|
||
only be used with classes whose metaclass is (or is derived from)
|
||
``AbstractClass`` below. A class containing at least one method
|
||
declared with this decorator that hasn't been overridden yet
|
||
cannot be instantiated. 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``.
|
||
|
||
``AbstractInstantiationError``
|
||
The exception raised when attempting to instantiate an abstract
|
||
class. It derives from ``TypeError``.
|
||
|
||
|
||
ABCs for Containers and Iterators
|
||
---------------------------------
|
||
|
||
XXX define: Iterable, Iterator, Sizeable (or Lengthy?), various Sets,
|
||
Mappings, Sequences. Also Hashable so we can define Immutable (which
|
||
adds to "read-only", does not subtract from "mutable", nor does
|
||
"mutable" add to "hashable" -- it adds to "read-only"). Also defines
|
||
how set, frozenset, list, tuple, dict, bytes and str derive from
|
||
these.
|
||
|
||
|
||
ABCs for Numbers
|
||
----------------
|
||
|
||
XXX define: Number, Complex, Real, Rational, Integer. Do we have a
|
||
use case for Cardinal (Integer >= 0)? Do we need Indexable (converts
|
||
to Integer using __index__).
|
||
|
||
|
||
Guidelines for Writing ABCs
|
||
---------------------------
|
||
|
||
XXX E.g. use @abstractmethod and Abstract base class; define abstract
|
||
methods that could be useful as an end point when called via a super
|
||
chain; keep abstract classes small, one per use case instead of one
|
||
per concept.
|
||
|
||
|
||
References
|
||
==========
|
||
|
||
.. [1] An Introduction to ABC's, by Talin
|
||
(http://mail.python.org/pipermail/python-3000/2007-April/006614.html)
|
||
|
||
.. [2] Incomplete implementation prototype, by GvR
|
||
(http://svn.python.org/view/sandbox/trunk/abc/)
|
||
|
||
|
||
Copyright
|
||
=========
|
||
|
||
This document has been placed in the public domain.
|
||
|
||
|
||
|
||
..
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
sentence-end-double-space: t
|
||
fill-column: 70
|
||
coding: utf-8
|
||
End:
|