Add pointer to implementation of @abstractmethod in C.
Change ABC framework description to only mention @abstractmethod and unconditionally propose it as a built-in. Some more editorializing; explain why we have BasicMapping.
This commit is contained in:
parent
f9b3dff1fb
commit
81cba80bfe
137
pep-3119.txt
137
pep-3119.txt
|
@ -16,9 +16,9 @@ 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".
|
||||
* An "ABC support framework" which defines a built-in decorator that
|
||||
can be used to define abstract methods. A class containing an
|
||||
abstract method that isn't overridden cannot be instantiated.
|
||||
|
||||
* Specific ABCs for containers and iterators, to be added to the
|
||||
collections module.
|
||||
|
@ -119,10 +119,10 @@ ones are kept.
|
|||
Specification
|
||||
=============
|
||||
|
||||
The specification follows the four categories listed in the abstract:
|
||||
The specification follows the 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.
|
||||
* An "ABC support framework" which defines a built-in decorator that
|
||||
make it easy to define ABCs, and mechanisms to support it.
|
||||
|
||||
* Specific ABCs for containers and iterators, to be added to the
|
||||
collections module.
|
||||
|
@ -131,58 +131,48 @@ The specification follows the four categories listed in the abstract:
|
|||
ABC Support Framework
|
||||
---------------------
|
||||
|
||||
We define the following four new built-in objects that help defining
|
||||
ABCs:
|
||||
We define a new built-in decorator, ``@abstractmethod``, to be used to
|
||||
declare abstract methods. 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). For example::
|
||||
|
||||
``@abstractmethod``
|
||||
A decorator used to declare abstract methods. This should only be
|
||||
used with classes whose class is derived from ``Abstract`` 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).
|
||||
|
||||
``AbstractClass``
|
||||
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``.
|
||||
|
||||
**Open issues:**
|
||||
|
||||
* 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):
|
||||
class A:
|
||||
@abstractmethod
|
||||
def foo(self): ...
|
||||
def foo(self): pass
|
||||
|
||||
and this::
|
||||
A() # raises TypeError
|
||||
|
||||
class C(Abstract):
|
||||
@abstractmethod
|
||||
def foo(self): ...
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
B() # raises TypeError
|
||||
|
||||
class C(A):
|
||||
def foo(self): print(42)
|
||||
|
||||
C() # works
|
||||
|
||||
**Implementation:** The ``@abstractmethod`` decorator sets the
|
||||
function attribute ``__isabstractmethod__`` to the value ``True``.
|
||||
The ``type.__new__`` method computes the type attribute
|
||||
``__abstractmethods__`` as the set of all method names that have an
|
||||
``__isabstractmethod__`` attribute whose value is true. It does this
|
||||
by combining the ``__abstractmethods__` attributes of the base
|
||||
classes, adding the names of all methods in the new class dict that
|
||||
have a true ``__isabstractmethod__`` attribute, and removing the names
|
||||
of all methods in the new class dict that don't have a true
|
||||
``__isabstractmethod__`` attribute. If the resulting
|
||||
``__abstractmethods__`` set is non-empty, the class is considered
|
||||
abstract, and attempts to instantiate it will raise ``TypeError``.
|
||||
(CPython can uses an internal flag ``Py_TPFLAGS_ABSTRACT`` to speed up
|
||||
this check [6]_.)
|
||||
|
||||
**Discussion:** Unlike C++ or Java, abstract methods as defined here
|
||||
may have an implementation. This implementation can be called via the
|
||||
``super`` mechanism from the class that overrides it. This could be
|
||||
useful as an end-point for a super-call in framework using a
|
||||
cooperative multiple-inheritance [7]_, [8]_.
|
||||
|
||||
|
||||
ABCs for Containers and Iterators
|
||||
|
@ -279,7 +269,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 issue:** Is ``Sized`` the best
|
||||
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
|
||||
|
@ -438,7 +428,16 @@ out of the scope of a pragmatic proposal like this.
|
|||
Mappings
|
||||
''''''''
|
||||
|
||||
These abstract classes represent various stages of mapping-ness.
|
||||
These abstract classes represent various stages of mapping-ness. The
|
||||
``Mapping`` class represents the most common read-only mapping API.
|
||||
However, code *accepting* a mapping is encouraged to check for the
|
||||
``BasicMapping`` ABC when iteration is not used. This allows for
|
||||
certain "black-box" implementations that can look up values by key but
|
||||
don't provide a convenient iteration API. A hypothetical example
|
||||
would be an interface to a hierarchical filesystem, where keys are
|
||||
pathnames relative to some root directory. Iterating over all
|
||||
pathnames would presumably take forever, as would counting the number
|
||||
of valid pathnames.
|
||||
|
||||
The built-in type ``dict`` derives from ``MutableMapping``.
|
||||
|
||||
|
@ -488,10 +487,6 @@ The built-in type ``dict`` derives from ``MutableMapping``.
|
|||
|
||||
**Open issues:**
|
||||
|
||||
* 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.
|
||||
|
||||
|
||||
|
@ -545,8 +540,8 @@ deriving from ``MutableSequence``, and (Unicode) character strings
|
|||
|
||||
**Open issues:** define the base interfaces for these so alternative
|
||||
implementations and subclasses know what they are in for. This may be
|
||||
the subject of a new PEP or PEPs (maybe PEP 358 can be co-opted for
|
||||
the ``bytes`` type).
|
||||
the subject of a new PEP or PEPs (PEP 358 should be co-opted for the
|
||||
``bytes`` type).
|
||||
|
||||
|
||||
ABCs for Numbers
|
||||
|
@ -555,16 +550,15 @@ ABCs for Numbers
|
|||
**Open issues:** Define: ``Number``, ``Complex``, ``Real``,
|
||||
``Rational``, ``Integer``. Maybe also ``Cardinal`` (``Integer`` >=
|
||||
0)? We probably also need ``Index``, which converts to ``Integer``
|
||||
using ``__index__``. This should probably be moved out to a separate
|
||||
PEP.
|
||||
using ``__index__``. This should be moved out to a separate PEP.
|
||||
|
||||
|
||||
Guidelines for Writing ABCs
|
||||
---------------------------
|
||||
|
||||
Some suggestions:
|
||||
Some suggestions for writing ABCs:
|
||||
|
||||
* Use ``@abstractmethod`` and the ``Abstract`` base class.
|
||||
* Use the ``@abstractmethod`` decorator.
|
||||
|
||||
* Define abstract methods that could be useful as an end point when
|
||||
called via a super chain.
|
||||
|
@ -575,8 +569,6 @@ Some suggestions:
|
|||
* Keep abstract classes small, one per use case instead of one per
|
||||
concept.
|
||||
|
||||
* What else?
|
||||
|
||||
|
||||
ABCs vs. Alternatives
|
||||
=====================
|
||||
|
@ -680,6 +672,15 @@ References
|
|||
.. [5] Charming Python: Scaling a new PEAK, by David Mertz
|
||||
(http://www-128.ibm.com/developerworks/library/l-cppeak2/)
|
||||
|
||||
.. [6] Implementation of @abstractmethod
|
||||
(http://python.org/sf/1706989)
|
||||
|
||||
.. [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
|
||||
(http://www.amazon.com/gp/product/0201433052)
|
||||
|
||||
|
||||
Copyright
|
||||
|
|
Loading…
Reference in New Issue