[Python-3000] PEP 3119 - Introducing Abstract Base Classes (original) (raw)
Jeffrey Yasskin jyasskin at gmail.com
Fri Apr 27 21:27:16 CEST 2007
- Previous message: [Python-3000] PEP 3119 - Introducing Abstract Base Classes
- Next message: [Python-3000] *View in abc.py not inheriting Iterable Re: PEP 3119 - Introducing Abstract Base Classes
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
This PEP says that no ABC defines init or a couple other methods. Is that a prohibition on ABCs in general, or just a comment about the ones defined here?
Can properties be abstract? How would one specify it? (Is that @abstractattribute?)
On the orderings: If I have a function foo(a, b) and I want to check whether they're totally ordered (perhaps sort() will use a topological sort when its argument's contents are only partially ordered.), how do I do it? "isinstance(a, TotallyOrdered) and isinstance(b, TotallyOrdered)" doesn't work since they may be in two different orders. "isinstance(a, TotallyOrdered) and type(a)==type(b)" doesn't work when you tend to inherit from concrete types. " isinstance(a, TotallyOrdered) and isinstance(b, TotallyOrdered) and (isinstance(a, type(b)) or isinstance(b, type(a))" fails when a and b are sibling subclasses of int. (I didn't think of this option; I think it was Jim Jewett's?) Searching up the hierarchy from a and b for the first concrete type, and checking if those are equal would be pretty reliable if types were singly-inherited, but with multiple inheritance, it would take more thought to get it right. Java's solution is to parametrize Comparable with the type that the subclass is comparable with. TotallyOrdered could specify an attribute on its subclasses for users to check against.
On 4/26/07, Guido van Rossum <guido at python.org> wrote:
After a fair amount of pre-discussion, I'm ready for the first official review of this PEP. The PEP is online at http://www.python.org/dev/peps/pep-3119/ . Here's a summary of open issues on which I could use more help (more details in the full text of the PEP below):
- Where should PartiallyOrdered and TotallyOrdered live? - Should we support comparison of different concrete set types? - Ditto for mapping types? - Ditto for sequence types? - Should Sequence derive from TotallyOrdered? - Should ComposableSet.or and friends be abstract or concrete? - If concrete, how should they create the result? - Do we need a non-composable hashable set type? - Ditto for a non-composable mutable set type? - Should we require that the iteration order for keys, values and items of a mapping are always consistent? - Which standard methods should sequences have? Of course, feel free to discuss any issues not marked as "open" as well. Full text of the PEP: PEP: 3119 Title: Introducing Abstract Base Classes Version: Revision:54986Revision: 54986 Revision:54986 Last-Modified: Date:2007−04−2611:24:07−0700(Thu,26Apr2007)Date: 2007-04-26 11:24:07 -0700 (Thu, 26 Apr 2007) Date:2007−04−2611:24:07−0700(Thu,26Apr2007) Author: Guido van Rossum <guido at python.org>, Talin <talin at acm.org> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 18-Apr-2007 Post-History: 26-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 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. 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 makes a set", "what makes a mapping" and "what makes a sequence". 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. The rest of the PEP uses "I" referring to the first author. 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. In addition, the ABCs define a minimal set of methods that establish the characteristic behavior of the type. Code that discriminates objects based on their ABC type can trust that those methods will always be present. Each of these methods are accompanied by an generalized abstract semantic definition that is described in the documentation for the ABC. These standard semantic definitions are not enforced, but are strongly recommended. Like all other things in Python, these promises are in the nature of a gentlemen's agreement, which in this case means that while the language does enforce some of the promises made in the ABC, it is up to the implementer of the concrete class to insure that the remaining ones are kept. Specification ============= The specification follows the categories listed in the abstract: * 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. ABC Support Framework --------------------- 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 (usingsuper
or direct invocation). For example:: class A: @abstractmethod def foo(self): pass A() # raises TypeError class B(A): pass B() # raises TypeError class C(A): def foo(self): print(42) C() # works Note: The@abstractmethod
decorator should only be used inside a class body. Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported. Implementation: The@abstractmethod
decorator sets the function attribute_isabstractmethod_
to the valueTrue
. Thetype._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 raiseTypeError
. (CPython can uses an internal flagPyTPFLAGSABSTRACT
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 thesuper
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 --------------------------------- Thecollections
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 technically valid but fairly useless; e.g._hash_
returns 0, and_iter_
returns an empty iterator. In general, the abstract methods represent the behavior of an empty container of the indicated type. Some ABCs also provide concrete (i.e. non-abstract) methods; for example, theIterator
class has an_iter_
method returning 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_
. 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 toobject
in the ABC hierarchy.PartiallyOrdered
This ABC defines the 4 inequality operations<
,<=
,>=
,>
. (Note that==
and!=
are defined byobject
.) Classes deriving from this ABC should implement a partial order as defined in mathematics. [9]TotallyOrdered
This ABC derives fromPartiallyOrdered
. It adds no new operations but implies a promise of stronger invariants. Classes deriving from this ABC should implement a total order as defined in mathematics. [10] Open issues: Where should these live? Thecollections
module doesn't seem right, but making them built-ins seems a slippery slope too. One Trick Ponies '''''''''''''''' These abstract classes represent single methods like_iter_
or_len_
.Hashable
The base class for classes defining_hash_
. The_hash_
method should return anInteger
(see "Numbers" below). The abstract_hash_
method always returns 0, which is a valid (albeit inefficient) implementation. Invariant: If classesC1
andC2
both derive fromHashable
, the conditiono1 == o2
must implyhash(o1) == hash(o2)
for all instanceso1
ofC1
and all instanceso2
ofC2
. IOW, two objects shouldn't compare equal but have different hash values. Another constraint is that hashable objects, once created, should never change their value (as compared by==
) or their hash value. If a class cannot guarantee this, it should not derive fromHashable
; if it cannot guarantee this for certain instances only,_hash_
for those instances should raise aTypeError
exception. Note: being an instance of this class does not imply that an object is immutable; e.g. a tuple containing a list as a member is not immutable; its_hash_
method raisesTypeError
.Iterable
The base class for classes defining_iter_
. The_iter_
method should always return an instance ofIterator
(see below). The abstract_iter_
method returns an empty iterator.Iterator
The base class for classes defining_next_
. This derives fromIterable
. The abstract_next_
method raisesStopIteration
. The concrete_iter_
method returnsself
.Sized
The base class for classes defining_len_
. The_len_
method should return anInteger
(see "Numbers" below) >= 0. The abstract_len_
method returns 0. Invariant: If a classC
derives fromSized
as well as fromIterable
, the invariantsum(1 for x in o) == len(o)
should hold for any instanceo
ofC
.Container
The base class for classes defining_contains_
. The_contains_
method should return abool
. The abstract_contains_
method returnsFalse
. Invariant: If a classC
derives fromContainer
as well as fromIterable
, then(x in o for x in o)
should be a generator yielding only True values for any instanceo
ofC
. Note: strictly speaking, there are three variants of this method's semantics. The first one is for sets and mappings, which is fast: O(1) or O(log N). The second one is for membership checking on sequences, which is slow: O(N). The third one is for subsequence checking on (character or byte) strings, which is also slow: O(N). Would it make sense to distinguish these? The signature of the third variant is different, since it takes a sequence (typically of the same type as the method's target) intead of an element. For now, I'm using the same type for all three. This means that is is possible forx in o
to be True even thoughx
is never yielded byiter(o)
. A suggested name for the third form isSearchable
. Sets '''' These abstract classes represent various stages of "set-ness". The most fundamental set operation is the membership test, written as ``x in sand implemented by
s.contains(x)``. This is already taken care of by the `Containerclass defined above. Therefore, we_ _define a set as a sized, iterable container for which certain_ _invariants from mathematical set theory hold._ _The built-in type
setderives from
MutableSet. The built-in_ _type
frozensetderives from
HashableSet._ _You might wonder why we require a set to be sized -- surely certain_ _infinite sets can be represented just fine in Python. For example,_ _the set of even integers could be defined like this::_ _class EvenIntegers(Container):_ _def _contains_(self, x):_ _return x % 2 == 0_ _However, such sets have rather limited practical value, and deciding_ _whether one such set is a subset of another would be difficult in_ _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 sized, iterable, partially ordered container, i.e. a_ _subclass of
Sized,
Iterable,
Containerand_ _
PartiallyOrdered. Not every subset of those three classes is_ _a set though! Sets have the additional invariant that each_ _element occurs only once (as can be determined by iteration), and_ _in addition sets define concrete operators that implement the_ _inequality operations as subclass/superclass tests. In general,_ _the invariants for finite sets in mathematics hold. [11]_ _Sets with different implementations can be compared safely,_ _(usually) efficiently and correctly using the mathematical_ _definitions of the subclass/superclass operations for finite sets._ _The ordering operations have concrete implementations; subclasses_ _may override these for speed but should maintain the semantics._ _Because
Setderives from
Sized,
_eq_may take a_ _shortcut and returns
Falseimmediately if two sets of unequal_ _length are compared. Similarly,
_le_may return
False_ _immediately if the first set has more members than the second set._ _Note that set inclusion implements only a partial ordering;_ _e.g.
{1, 2}and
{1, 3}are not ordered (all three of_ _
<,
==and
>return
Falsefor these arguments)._ _Sets cannot be ordered relative to mappings or sequences, but they_ _can be compared to those for equality (and then they always_ _compare unequal)._ _**Note:** the
issubsetand
issupersetmethods found on the_ _set type in Python 2 are not supported, as these are mostly just_ _aliases for
_le_and
_ge_._ _**Open issues:** should we define comparison of instances of_ _different concrete set types this way?_ _
ComposableSet_ _This is a subclass of
Setthat defines abstract operators to_ _compute union, intersection, symmetric and asymmetric difference,_ _respectively
_or_,
_and_,
_xor_and
_sub_._ _These operators should return instances of
ComposableSet. The_ _abstract implementations return no meaningful values but raise_ _
NotImplementedError; this is because any generic_ _implementation would have to create new instances but the ABCs_ _don't (and shouldn't, IMO) provide an API for creating new_ _instances. The implementations of these operators should ensure_ _that the results match the mathematical definition of set_ _composition. [11]_ _**Open issues:** Should
_or_and friends be abstract or_ _concrete methods? Making them abstract means that every_ _ComposableSet implementation must reimplement all of them. But_ _making them concrete begs the question of the actual return type:_ _since the ABC doesn't (and IMO shouldn't) define the constructor_ _signature for subclasses, the concrete implementations in the ABC_ _don't have an API to construct a new instance given an iterable._ _Perhaps the right choice is to have a static concrete factory_ _function
fromiterablewhich takes an iterable and returns_ _a
ComposableSetinstance. Subclasses can override this and_ _benefit from the default implementations of
_or_etc.; or_ _they can override
_or_if they want to._ _
HashableSet_ _This is a subclass of both
ComposableSetand
Hashable. It_ _implements a concrete
_hash_method that subclasses should_ _not override; or if they do, the subclass should compute the same_ _hash value. This is so that sets with different implementations_ _still hash to the same value, so they can be used interchangeably_ _as dictionary keys. (A similar constraint exists on the hash_ _values for different types of numbers and strings.)_ _**Open issues:** Spell out the hash algorithm. Should there be_ _another ABC that derives from Set and Hashable, but not from_ _Composable?_ _
MutableSet_ _This is a subclass of
ComposableSetimplementing additional_ _operations to add and remove elements. The supported methods have_ _the semantics known from the
settype in Python 2 (except_ _for
discard, which is modeled after Java):_ _
.add(x)_ _Abstract method returning a
boolthat adds the element_ _
xif it isn't already in the set. It should return_ _
Trueif
xwas added,
Falseif it was already_ _there. The abstract implementation raises_ _
NotImplementedError._ _
.discard(x)_ _Abstract method returning a
boolthat removes the element_ _
xif present. It should return
Trueif the element_ _was present and
Falseif it wasn't. The abstract_ _implementation raises
NotImplementedError._ _
.pop()_ _Concrete method that removes an arbitrary item. If the set is_ _empty, it raises
KeyError. The default implementation_ _removes the first item returned by the set's iterator._ _
.toggle(x)_ _Concrete method returning a
boolthat adds x to the set if_ _it wasn't there, but removes it if it was there. It should_ _return
Trueif
xwas added,
Falseif it was_ _removed._ _
.clear()_ _Concrete method that empties the set. The default_ _implementation repeatedly calls
self.pop()until_ _
KeyErroris caught. (**Note:** this is likely much slower_ _than simply creating a new set, even if an implementation_ _overrides it with a faster approach; but in some cases object_ _identity is important.)_ _This also supports the in-place mutating operations
|=,_ _
&=,
^=,
-=. These are concrete methods whose right_ _operand can be an arbitrary
Iterable, except for
&=, whose_ _right operand must be a
Container. This ABC does not support_ _the named methods present on the built-in concrete
settype_ _that perform (almost) the same operations._ _Mappings_ _''''''''_ _These abstract classes represent various stages of mapping-ness. The_ _
Mappingclass represents the most common read-only mapping API._ _However, code *accepting* a mapping is encouraged to check for the_ _
BasicMappingABC 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
dictderives from
MutableMapping._ _
BasicMapping_ _A subclass of
Containerdefining the following methods:_ _
._getitem_(key)_ _Abstract method that returns the value corresponding to_ _
key, or raises
KeyError. The implementation always_ _raises
KeyError._ _
.get(key, default=None)_ _Concrete method returning
self[key]if this does not raise_ _
KeyError, and the
defaultvalue if it does._ _
._contains_()_ _Concrete method returning
Trueif
self[key]does not_ _raise
KeyError, and
Falseif it does._ _
Mapping_ _A subclass of
BasicMapping,
Iterableand
Sized. The_ _keys of a mapping naturally form a set. The (key, value) pairs_ _are also referred to as items. The items also form a set._ _Methods:_ _
_len__ _Abstract method returning the length of the key set._ _
_iter__ _Abstract method returning each key in the key set exactly once._ _
_eq__ _Concrete method for comparing mappings. Two mappings, even_ _with different implementations, can be compared for equality,_ _and are considered equal if and only iff their item sets are_ _equal. **Open issues:** should we define comparison of_ _instances of different concrete mapping types this way?_ _
keys_ _Concrete method returning the key set as a
Set. The_ _default concrete implementation returns a "view" on the key_ _set (meaning if the underlying mapping is modified, the view's_ _value changes correspondingly); subclasses are not required to_ _return a view but they should return a
Set._ _
items_ _Concrete method returning the items as a
Set. The default_ _concrete implementation returns a "view" on the item set;_ _subclasses are not required to return a view but they should_ _return a
Set._ _
values_ _Concrete method returning the values as a sized, iterable_ _container (not a set!). The default concrete implementation_ _returns a "view" on the values of the mapping; subclasses are_ _not required to return a view but they should return a sized,_ _iterable container._ _The following invariant should hold for any mapping
m::_ _set(m.items()) == set(zip(m.keys(), m.values()))_ _i.e. iterating over the keys and the values in parallel should_ _return *corresponding* keys and values. **Open issues:** Should_ _this always be required? How about the stronger invariant using_ _
list()instead of
set()?_ _
HashableMapping_ _A subclass of
Mappingand
Hashable. The values should be_ _instances of
Hashable. The concrete
_hash_method_ _should be equal to
hash(m.items())._ _
MutableMapping_ _A subclass of
Mappingthat also implements some standard_ _mutating methods. Abstract methods include
_setitem_,_ _
_delitem_. Concrete methods include
pop,
popitem,_ _
clear,
update. **Note:**
setdefaultis *not* included._ _**Open issues:** Write out the specs for the methods._ _Sequences_ _'''''''''_ _These abstract classes represent various stages of sequence-ness._ _The built-in
listand
bytestypes derive from_ _
MutableSequence. The built-in
tupleand
strtypes derive_ _from
HashableSequence._ _
Sequence_ _A subclass of
Iterable,
Sized,
Container. It_ _defines a new abstract method
_getitem_that has a somewhat_ _complicated signature: when called with an integer, it returns an_ _element of the sequence or raises
IndexError; when called with_ _a
sliceobject, it returns another
Sequence. The concrete_ _
_iter_method iterates over the elements using_ _
_getitem_with integer arguments 0, 1, and so on, until_ _
IndexErroris raised. The length should be equal to the_ _number of values returned by the iterator._ _**Open issues:** Other candidate methods, which can all have_ _default concrete implementations that only depend on
_len__ _and
_getitem_with an integer argument: _reversed_, index,_ _count, _add_, _mul_, _eq_, _lt_, _le_._ _
HashableSequence_ _A subclass of
Sequenceand
Hashable. The concrete_ _
_hash_method should implements the hashing algorithms used_ _by tuples in Python 2._ _
MutableSequence_ _A subclass of
Sequenceadding some standard mutating methods._ _Abstract mutating methods:
_setitem_(for integer indices as_ _well as slices),
_delitem_(ditto),
insert,
append,_ _
reverse. Concrete mutating methods:
extend,
pop,_ _
remove. Concrete mutating operators:
+=,
*=(these_ _mutate the object in place). **Note:** this does not define_ _
sort()-- that is only required to exist on genuine
list_ _instances._ _**Open issues:** If all the elements of a sequence are totally_ _ordered, the sequence itself can be totally ordered with respect to_ _other sequences containing corresponding items of the same type._ _Should we reflect this by making
Sequencederive from_ _
TotallyOrdered? Or
Partiallyordered? Also, we could easily_ _define comparison of sequences of different types, so that e.g._ _
(1, 2, 3) == [1, 2, 3]and
(1, 2) < [1, 2, 3]. Should we?_ _(It might imply
["a", "b"] == "ab"and
[1, 2] == b"\1\2".)_ _Strings_ _-------_ _Python 3000 has two built-in string types: byte strings (
bytes),_ _deriving from
MutableSequence, and (Unicode) character strings_ _(
str), deriving from
HashableSequence. They also derive from_ _
TotallyOrdered. If we were to introduce
Searchable, they_ _would also derive from that._ _**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 (PEP 358 should be co-opted for the_ _
bytestype)._ _Numbers_ _-------_ _ABCs for numerical types are defined in PEP 3141._ _Guidelines for Writing ABCs_ _---------------------------_ _Some suggestions for writing ABCs:_ _* Use the
@abstractmethoddecorator._ _* 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)._ _* Keep abstract classes small, one per use case instead of one per_ _concept._ _ABCs vs. Alternatives_ _=====================_ _In this section I will attempt to compare and contrast ABCs to other_ _approaches that have been proposed._ _ABCs vs. Duck Typing_ _--------------------_ _Does the introduction of ABCs mean the end of Duck Typing? I don't_ _think so. Python will not require that a class derives from_ _
BasicMappingor
Sequencewhen it defines a
_getitem__ _method, nor will the
x[y]syntax require that
xis an instance_ _of either ABC. You will still be able to assign any "file-like"_ _object to
sys.stdout, as long as it has a
writemethod._ _Of course, there will be some carrots to encourage users to derive_ _from the appropriate base classes; these vary from default_ _implementations for certain functionality to an improved ability to_ _distinguish between mappings and sequences. But there are no sticks._ _If
hasattr(x, _len_)works for you, great! ABCs are intended to_ _solve problems that don't have a good solution at all in Python 2,_ _such as distinguishing between mappings and sequences._ _ABCs vs. Generic Functions_ _--------------------------_ _ABCs are compatible with Generic Functions (GFs). For example, my own_ _Generic Functions implementation [4] uses the classes (types) of the_ _arguments as the dispatch key, allowing derived classes to override_ _base classes. Since (from Python's perspective) ABCs are quite_ _ordinary classes, using an ABC in the default implementation for a GF_ _can be quite appropriate. For example, if I have an overloaded_ _
prettyprintfunction, it would make total sense to define_ _pretty-printing of sets like this::_ _@prettyprint.register(Set)_ _def ppset(s):_ _return "{" + ... + "}" # Details left as an exercise_ _and implementations for specific subclasses of Set could be added_ _easily._ _I believe ABCs also won't present any problems for RuleDispatch,_ _Phillip Eby's GF implementation in PEAK [5]._ _Of course, GF proponents might claim that GFs (and concrete, or_ _implementation, classes) are all you need. But even they will not_ _deny the usefulness of inheritance; and one can easily consider the_ _ABCs proposed in this PEP as optional implementation base classes;_ _there is no requirement that all user-defined mappings derive from_ _
BasicMapping``. ABCs vs. Interfaces ------------------- ABCs are not intrinsically incompatible with Interfaces, but there is considerable overlap. For now, I'll leave it to proponents of Interfaces to explain why Interfaces are better. I expect that much of the work that went into e.g. defining the various shades of "mapping-ness" and the nomenclature could easily be adapted for a proposal to use Interfaces instead of ABCs. "Interfaces" in this context refers to a set of proposals for additional metadata elements attached to a class which are not part of the regular class hierarchy, but do allow for certain types of inheritance testing. Such metadata would be designed, at least in some proposals, so as to be easily mutable by an application, allowing application writers to override the normal classification of an object. The drawback to this idea of attaching mutable metadata to a class is that classes are shared state, and mutating them may lead to conflicts of intent. Additionally, the need to override the classification of an object can be done more cleanly using generic functions: In the 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. 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/) .. [3] Possible Python 3K Class Tree?, wiki page created by Bill Janssen (http://wiki.python.org/moin/AbstractBaseClasses) .. [4] Generic Functions implementation, by GvR (http://svn.python.org/view/sandbox/trunk/overload/) .. [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) .. [9] Partial order, in Wikipedia (http://en.wikipedia.org/wiki/Partialorder) .. [10] Total order, in Wikipedia (http://en.wikipedia.org/wiki/Totalorder) .. [11] Finite set, in Wikipedia (http://en.wikipedia.org/wiki/Finiteset) 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: -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Python-3000 mailing list Python-3000 at python.org http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/jyasskin%40gmail.com
-- Namasté, Jeffrey Yasskin http://jeffrey.yasskin.info/
"Religion is an improper response to the Divine." — "Skinny Legs and All", by Tom Robbins
- Previous message: [Python-3000] PEP 3119 - Introducing Abstract Base Classes
- Next message: [Python-3000] *View in abc.py not inheriting Iterable Re: PEP 3119 - Introducing Abstract Base Classes
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]