From 81cba80bfeb476e887e38d8200b6a31e7fa2965a Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 25 Apr 2007 00:17:23 +0000 Subject: [PATCH] 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. --- pep-3119.txt | 137 ++++++++++++++++++++++++++------------------------- 1 file changed, 69 insertions(+), 68 deletions(-) diff --git a/pep-3119.txt b/pep-3119.txt index 5a8ebec07..414f7bc10 100644 --- a/pep-3119.txt +++ b/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