Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 3119 – Introducing Abstract Base Classes

Author:
Guido van Rossum <guido at python.org>, Talin <viridia at gmail.com>
Status:
Final
Type:
Standards Track
Created:
18-Apr-2007
Python-Version:
3.0
Post-History:
26-Apr-2007, 11-May-2007

Table of Contents

Abstract

This is a proposal to add Abstract Base Class (ABC) support to Python3000. It proposes:

  • A way to overloadisinstance() andissubclass().
  • A new moduleabc which serves as an “ABC support framework”. Itdefines a metaclass for use with ABCs and a decorator that can beused to define abstract methods.
  • Specific ABCs for containers and iterators, to be added to thecollections module.

Much of the thinking that went into the proposal is not about thespecific mechanism of ABCs, as contrasted with Interfaces or GenericFunctions (GFs), but about clarifying philosophical issues like “whatmakes a set”, “what makes a mapping” and “what makes a sequence”.

There’s also a companionPEP 3141, which defines ABCs for numerictypes.

Acknowledgements

Talin wrote the Rationale below[1] as well as most of the section onABCs vs. Interfaces. For that alone he deserves co-authorship. Therest of the PEP uses “I” referring to the first author.

Rationale

In the domain of object-oriented programming, the usage patterns forinteracting 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 givenmethod may run different code depending on the type of an object.

Inspection means the ability for external code (outside of theobject’s methods) to examine the type or properties of that object,and make decisions on how to treat that object based on thatinformation.

Both usage patterns serve the same general end, which is to be able tosupport the processing of diverse and potentially novel objects in auniform way, but at the same time allowing processing decisions to becustomized 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 anearlier, procedural programming style. However, in practice this viewis simply too dogmatic and inflexible, and leads to a kind of designrigidity that is very much at odds with the dynamic nature of alanguage like Python.

In particular, there is often a need to process objects in a way thatwasn’t anticipated by the creator of the object class. It is notalways the best solution to build in to every object methods thatsatisfy the needs of every possible user of that object. Moreover,there are many powerful dispatch philosophies that are in directcontrast to the classic OOP requirement of behavior being strictlyencapsulated within an object, examples being rule or pattern-matchdriven logic.

On the other hand, one of the criticisms of inspection by classicOOP theorists is the lack of formalisms and the ad hoc nature of whatis being inspected. In a language such as Python, in which almost anyaspect of an object can be reflected and directly accessed by externalcode, there are many different ways to test whether an object conformsto a particular protocol or not. For example, if asking ‘is thisobject a mutable sequence container?’, one can look for a base classof ‘list’, or one can look for a method named ‘__getitem__’. But notethat although these tests may seem obvious, neither of them arecorrect, as one generates false negatives, and the other falsepositives.

The generally agreed-upon remedy is to standardize the tests, andgroup them into a formal arrangement. This is most easily done byassociating with each class a set of standard testable properties,either via the inheritance mechanism or some other means. Each testcarries with it a set of promises: it contains a promise about thegeneral behavior of the class, and a promise as to what other classmethods will be available.

This PEP proposes a particular strategy for organizing these testsknown as Abstract Base Classes, or ABC. ABCs are simply Pythonclasses that are added into an object’s inheritance tree to signalcertain features of that object to an external inspector. Tests aredone usingisinstance(), and the presence of a particular ABCmeans that the test has passed.

In addition, the ABCs define a minimal set of methods that establishthe characteristic behavior of the type. Code that discriminatesobjects based on their ABC type can trust that those methods willalways be present. Each of these methods are accompanied by angeneralized abstract semantic definition that is described in thedocumentation for the ABC. These standard semantic definitions arenot enforced, but are strongly recommended.

Like all other things in Python, these promises are in the nature of afriendly agreement, which in this case means that while thelanguage does enforce some of the promises made in the ABC, it is upto the implementer of the concrete class to insure that the remainingones are kept.

Specification

The specification follows the categories listed in the abstract:

  • A way to overloadisinstance() andissubclass().
  • A new moduleabc which serves as an “ABC support framework”. Itdefines a metaclass for use with ABCs and a decorator that can beused to define abstract methods.
  • Specific ABCs for containers and iterators, to be added to thecollections module.

Overloadingisinstance() andissubclass()

During the development of this PEP and of its companion,PEP 3141, werepeatedly faced the choice between standardizing more, fine-grainedABCs or fewer, coarse-grained ones. For example, at one stage, PEP3141 introduced the following stack of base classes used for complexnumbers: MonoidUnderPlus, AdditiveGroup, Ring, Field, Complex (eachderived from the previous). And the discussion mentioned severalother algebraic categorizations that were left out: Algebraic,Transcendental, and IntegralDomain, and PrincipalIdealDomain. Inearlier versions of the current PEP, we considered the use cases forseparate classes like Set, ComposableSet, MutableSet, HashableSet,MutableComposableSet, HashableComposableSet.

The dilemma here is that we’d rather have fewer ABCs, but then whatshould a user do who needs a less refined ABC? Consider e.g. theplight of a mathematician who wants to define their own kind ofTranscendental numbers, but also wants float and int to be consideredTranscendental.PEP 3141 originally proposed to patch float.__bases__for that purpose, but there are some good reasons to keep the built-intypes immutable (for one, they are shared between all Pythoninterpreters running in the same address space, as is used bymod_python[16]).

Another example would be someone who wants to define a genericfunction (PEP 3124) for any sequence that has anappend() method.TheSequence ABC (see below) doesn’t promise theappend()method, whileMutableSequence requires not onlyappend() butalso various other mutating methods.

To solve these and similar dilemmas, the next section will propose ametaclass for use with ABCs that will allow us to add an ABC as a“virtual base class” (not the same concept as in C++) to any class,including to another ABC. This allows the standard library to defineABCsSequence andMutableSequence and register these asvirtual base classes for built-in types likebasestring,tupleandlist, so that for example the following conditions are alltrue:

isinstance([],Sequence)issubclass(list,Sequence)issubclass(list,MutableSequence)isinstance((),Sequence)notissubclass(tuple,MutableSequence)isinstance("",Sequence)issubclass(bytearray,MutableSequence)

The primary mechanism proposed here is to allow overloading thebuilt-in functionsisinstance() andissubclass(). Theoverloading works as follows: The callisinstance(x,C) firstchecks whetherC.__instancecheck__ exists, and if so, callsC.__instancecheck__(x) instead of its normal implementation.Similarly, the callissubclass(D,C) first checks whetherC.__subclasscheck__ exists, and if so, callsC.__subclasscheck__(D) instead of its normal implementation.

Note that the magic names are not__isinstance__ and__issubclass__; this is because the reversal of the argumentscould cause confusion, especially for theissubclass() overloader.

A prototype implementation of this is given in[12].

Here is an example with (naively simple) implementations of__instancecheck__ and__subclasscheck__:

classABCMeta(type):def__instancecheck__(cls,inst):"""Implement isinstance(inst, cls)."""returnany(cls.__subclasscheck__(c)forcin{type(inst),inst.__class__})def__subclasscheck__(cls,sub):"""Implement issubclass(sub, cls)."""candidates=cls.__dict__.get("__subclass__",set())|{cls}returnany(cincandidatesforcinsub.mro())classSequence(metaclass=ABCMeta):__subclass__={list,tuple}assertissubclass(list,Sequence)assertissubclass(tuple,Sequence)classAppendableSequence(Sequence):__subclass__={list}assertissubclass(list,AppendableSequence)assertisinstance([],AppendableSequence)assertnotissubclass(tuple,AppendableSequence)assertnotisinstance((),AppendableSequence)

The next section proposes a full-fledged implementation.

Theabc Module: an ABC Support Framework

The new standard library moduleabc, written in pure Python,serves as an ABC support framework. It defines a metaclassABCMeta and decorators@abstractmethod and@abstractproperty. A sample implementation is given by[13].

TheABCMeta class overrides__instancecheck__ and__subclasscheck__ and defines aregister method. Theregister method takes one argument, which must be a class; afterthe callB.register(C), the callissubclass(C,B) will returnTrue, by virtue ofB.__subclasscheck__(C) returning True.Also,isinstance(x,B) is equivalent toissubclass(x.__class__,B)orissubclass(type(x),B). (It is possibletype(x) andx.__class__ are not the same object, e.g. when x is a proxyobject.)

These methods are intended to be called on classes whose metaclassis (derived from)ABCMeta; for example:

fromabcimportABCMetaclassMyABC(metaclass=ABCMeta):passMyABC.register(tuple)assertissubclass(tuple,MyABC)assertisinstance((),MyABC)

The last two asserts are equivalent to the following two:

assertMyABC.__subclasscheck__(tuple)assertMyABC.__instancecheck__(())

Of course, you can also directly subclass MyABC:

classMyClass(MyABC):passassertissubclass(MyClass,MyABC)assertisinstance(MyClass(),MyABC)

Also, of course, a tuple is not aMyClass:

assertnotissubclass(tuple,MyClass)assertnotisinstance((),MyClass)

You can register another class as a subclass ofMyClass:

MyClass.register(list)assertissubclass(list,MyClass)assertissubclass(list,MyABC)

You can also register another ABC:

classAnotherClass(metaclass=ABCMeta):passAnotherClass.register(basestring)MyClass.register(AnotherClass)assertisinstance(str,MyABC)

That last assert requires tracing the following superclass-subclassrelationships:

MyABC->MyClass(usingregularsubclassing)MyClass->AnotherClass(usingregistration)AnotherClass->basestring(usingregistration)basestring->str(usingregularsubclassing)

Theabc module also defines a new decorator,@abstractmethod,to be used to declare abstract methods. A class containing at leastone method declared with this decorator that hasn’t been overriddenyet cannot be instantiated. Such methods may be called from theoverriding method in the subclass (usingsuper or directinvocation). For example:

fromabcimportABCMeta,abstractmethodclassA(metaclass=ABCMeta):@abstractmethoddeffoo(self):passA()# raises TypeErrorclassB(A):passB()# raises TypeErrorclassC(A):deffoo(self):print(42)C()# works

Note: The@abstractmethod decorator should only be usedinside a class body, and only for classes whose metaclass is (derivedfrom)ABCMeta. Dynamically adding abstract methods to a class, orattempting to modify the abstraction status of a method or class onceit is created, are not supported. The@abstractmethod onlyaffects subclasses derived using regular inheritance; “virtualsubclasses” registered with theregister() method are not affected.

Implementation: The@abstractmethod decorator sets thefunction attribute__isabstractmethod__ to the valueTrue.TheABCMeta.__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 thisby combining the__abstractmethods__ attributes of the baseclasses, adding the names of all methods in the new class dict thathave a true__isabstractmethod__ attribute, and removing the namesof 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 consideredabstract, and attempts to instantiate it will raiseTypeError.(If this were implemented in CPython, an internal flagPy_TPFLAGS_ABSTRACT could be used to speed up this check[6].)

Discussion: Unlike Java’s abstract methods or C++’s pure abstractmethods, abstract methods as defined here may have an implementation.This implementation can be called via thesuper mechanism from theclass that overrides it. This could be useful as an end-point for asuper-call in framework using cooperative multiple-inheritance[7],[8].

A second decorator,@abstractproperty, is defined in order todefine abstract data attributes. Its implementation is a subclass ofthe built-inproperty class that adds an__isabstractmethod__attribute:

classabstractproperty(property):__isabstractmethod__=True

It can be used in two ways:

classC(metaclass=ABCMeta):# A read-only property:@abstractpropertydefreadonly(self):returnself.__x# A read-write property (cannot use decorator syntax):defgetx(self):returnself.__xdefsetx(self,value):self.__x=valuex=abstractproperty(getx,setx)

Similar to abstract methods, a subclass inheriting an abstractproperty (declared using either the decorator syntax or the longerform) cannot be instantiated unless it overrides that abstractproperty with a concrete property.

ABCs for Containers and Iterators

Thecollections module will define ABCs necessary and sufficientto work with sets, mappings, sequences, and some helper types such asiterators and dictionary views. All ABCs have the above-mentionedABCMeta as their metaclass.

The ABCs provide implementations of their abstract methods that aretechnically valid but fairly useless; e.g.__hash__ returns 0, and__iter__ returns an empty iterator. In general, the abstractmethods represent the behavior of an empty container of the indicatedtype.

Some ABCs also provide concrete (i.e. non-abstract) methods; forexample, theIterator class has an__iter__ method returningitself, fulfilling an important invariant of iterators (which inPython 2 has to be implemented anew by each iterator class). TheseABCs can be considered “mix-in” classes.

No ABCs defined in the PEP override__init__,__new__,__str__ or__repr__. Defining a standard constructorsignature would unnecessarily constrain custom container types, forexample Patricia trees or gdbm files. Defining a specific stringrepresentation for a collection is similarly left up to individualimplementations.

Note: There are no ABCs for ordering operations (__lt__,__le__,__ge__,__gt__). Defining these in a base class(abstract or not) runs into problems with the accepted type for thesecond operand. For example, if classOrdering defined__lt__, one would assume that for anyOrdering instancesxandy,x<y would be defined (even if it just defines apartial ordering). But this cannot be the case: If bothlist andstr derived fromOrdering, this would imply that[1,2]<(1,2) should be defined (and presumably return False), while infact (in Python 3000!) such “mixed-mode comparisons” operations areexplicitly forbidden and raiseTypeError. SeePEP 3100 and[14]for more information. (This is a special case of a more general issuewith operations that take another argument of the same type).

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 an integer. The abstract__hash__ method always returns 0, which is a valid (albeitinefficient) implementation.Invariant: If classesC1 andC2 both derive fromHashable, the conditiono1==o2must implyhash(o1)==hash(o2) for all instanceso1 ofC1 and all instanceso2 ofC2. In other words, twoobjects should never compare equal if they have different hashvalues.

Another constraint is that hashable objects, once created, shouldnever change their value (as compared by==) or their hashvalue. If a class cannot guarantee this, it should not derivefromHashable; if it cannot guarantee this for certaininstances,__hash__ for those instances should raise aTypeError exception.

Note: being an instance of this class does not imply that anobject is immutable; e.g. a tuple containing a list as a member isnot immutable; its__hash__ method raisesTypeError.(This is because it recursively tries to compute the hash of eachmember; if a member is unhashable it raisesTypeError.)

Iterable
The base class for classes defining__iter__. The__iter__ method should always return an instance ofIterator (see below). The abstract__iter__ methodreturns an empty iterator.
Iterator
The base class for classes defining__next__. This derivesfromIterable. The abstract__next__ method raisesStopIteration. The concrete__iter__ method returnsself. Note the distinction betweenIterable andIterator: anIterable can be iterated over, i.e. supportsthe__iter__ methods; anIterator is what the built-infunctioniter() returns, i.e. supports the__next__method.
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 aclassC derives fromSized as well as fromIterable,the invariantsum(1forxinc)==len(c) should hold for anyinstancec ofC.
Container
The base class for classes defining__contains__. The__contains__ method should return abool. The abstract__contains__ method returnsFalse.Invariant: If aclassC derives fromContainer as well as fromIterable, then(xincforxinc) should be a generatoryielding only True values for any instancec ofC.

Open issues: Conceivably, instead of using the ABCMeta metaclass,these classes could override__instancecheck__ and__subclasscheck__ to check for the presence of the applicablespecial method; for example:

classSized(metaclass=ABCMeta):@abstractmethoddef__hash__(self):return0@classmethoddef__instancecheck__(cls,x):returnhasattr(x,"__len__")@classmethoddef__subclasscheck__(cls,C):returnhasattr(C,"__bases__")andhasattr(C,"__len__")

This has the advantage of not requiring explicit registration.However, the semantics are hard to get exactly right given the confusingsemantics of instance attributes vs. class attributes, and that aclass is an instance of its metaclass; the check for__bases__ isonly an approximation of the desired semantics.Strawman: Let’sdo it, but let’s arrange it in such a way that the registration APIalso works.

Sets

These abstract classes represent read-only sets and mutable sets. Themost fundamental set operation is the membership test, written asxins and implemented bys.__contains__(x). This operation isalready defined by theContainer class defined above. Therefore,we define a set as a sized, iterable container for which certaininvariants from mathematical set theory hold.

The built-in typeset derives fromMutableSet. The built-intypefrozenset derives fromSet andHashable.

Set
This is a sized, iterable container, i.e., a subclass ofSized,Iterable andContainer. Not every subclass ofthose three classes is a set though! Sets have the additionalinvariant that each element occurs only once (as can be determinedby iteration), and in addition sets define concrete operators thatimplement the inequality operations as subset/superset tests.In general, the invariants for finite sets in mathematicshold.[11]

Sets with different implementations can be compared safely,(usually) efficiently and correctly using the mathematicaldefinitions of the subset/supeset operations for finite sets.The ordering operations have concrete implementations; subclassesmay override these for speed but should maintain the semantics.BecauseSet derives fromSized,__eq__ may take ashortcut and returnFalse immediately if two sets of unequallength are compared. Similarly,__le__ may returnFalseimmediately 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> returnFalse for these arguments).Sets cannot be ordered relative to mappings or sequences, but theycan be compared to those for equality (and then they alwayscompare unequal).

This class also defines concrete operators to compute union,intersection, symmetric and asymmetric difference, respectively__or__,__and__,__xor__ and__sub__. Theseoperators should return instances ofSet. The defaultimplementations call the overridable class method_from_iterable() with an iterable argument. This factorymethod’s default implementation returns afrozenset instance;it may be overridden to return another appropriateSetsubclass.

Finally, this class defines a concrete method_hash whichcomputes the hash value from the elements. Hashable subclasses ofSet can implement__hash__ by calling_hash or theycan reimplement the same algorithm more efficiently; but thealgorithm implemented should be the same. Currently the algorithmis fully specified only by the source code[15].

Note: theissubset andissuperset methods found on theset type in Python 2 are not supported, as these are mostly justaliases for__le__ and__ge__.

MutableSet
This is a subclass ofSet implementing additional operationsto add and remove elements. The supported methods have thesemantics known from theset type in Python 2 (except fordiscard, which is modeled after Java):
.add(x)
Abstract method returning abool that adds the elementx if it isn’t already in the set. It should returnTrue ifx was added,False if it was alreadythere. The abstract implementation raisesNotImplementedError.
.discard(x)
Abstract method returning abool that removes the elementx if present. It should returnTrue if the elementwas present andFalse if it wasn’t. The abstractimplementation raisesNotImplementedError.
.pop()
Concrete method that removes and returns an arbitrary item.If the set is empty, it raisesKeyError. The defaultimplementation removes the first item returned by the set’siterator.
.toggle(x)
Concrete method returning abool that adds x to the set ifit wasn’t there, but removes it if it was there. It shouldreturnTrue ifx was added,False if it wasremoved.
.clear()
Concrete method that empties the set. The defaultimplementation repeatedly callsself.pop() untilKeyError is caught. (Note: this is likely much slowerthan simply creating a new set, even if an implementationoverrides it with a faster approach; but in some cases objectidentity is important.)

This also supports the in-place mutating operations|=,&=,^=,-=. These are concrete methods whose rightoperand can be an arbitraryIterable, except for&=, whoseright operand must be aContainer. This ABC does not providethe named methods present on the built-in concreteset typethat perform (almost) the same operations.

Mappings

These abstract classes represent read-only mappings and mutablemappings. TheMapping class represents the most common read-onlymapping API.

The built-in typedict derives fromMutableMapping.

Mapping
A subclass ofContainer,Iterable andSized. The keysof a mapping naturally form a set. The (key, value) pairs (whichmust be tuples) are also referred to as items. The items alsoform a set. Methods:
.__getitem__(key)
Abstract method that returns the value corresponding tokey, or raisesKeyError. The implementation alwaysraisesKeyError.
.get(key,default=None)
Concrete method returningself[key] if this does not raiseKeyError, and thedefault value if it does.
.__contains__(key)
Concrete method returningTrue ifself[key] does notraiseKeyError, andFalse if it does.
.__len__()
Abstract method returning the number of distinct keys (i.e.,the length of the key set).
.__iter__()
Abstract method returning each key in the key set exactly once.
.keys()
Concrete method returning the key set as aSet. Thedefault concrete implementation returns a “view” on the keyset (meaning if the underlying mapping is modified, the view’svalue changes correspondingly); subclasses are not required toreturn a view but they should return aSet.
.items()
Concrete method returning the items as aSet. The defaultconcrete implementation returns a “view” on the item set;subclasses are not required to return a view but they shouldreturn aSet.
.values()
Concrete method returning the values as a sized, iterablecontainer (not a set!). The default concrete implementationreturns a “view” on the values of the mapping; subclasses arenot required to return a view but they should return a sized,iterable container.

The following invariants should hold for any mappingm:

len(m.values())==len(m.keys())==len(m.items())==len(m)[valueforvalueinm.values()]==[m[key]forkeyinm.keys()][itemforiteminm.items()]==[(key,m[key])forkeyinm.keys()]

i.e. iterating over the items, keys and values should returnresults in the same order.

MutableMapping
A subclass ofMapping that also implements some standardmutating methods. Abstract methods include__setitem__,__delitem__. Concrete methods includepop,popitem,clear,update.Note:setdefault isnot included.Open issues: Write out the specs for the methods.

Sequences

These abstract classes represent read-only sequences and mutablesequences.

The built-inlist andbytes types derive fromMutableSequence. The built-intuple andstr types derivefromSequence andHashable.

Sequence
A subclass ofIterable,Sized,Container. Itdefines a new abstract method__getitem__ that has a somewhatcomplicated signature: when called with an integer, it returns anelement of the sequence or raisesIndexError; when called withaslice object, it returns anotherSequence. The concrete__iter__ method iterates over the elements using__getitem__ with integer arguments 0, 1, and so on, untilIndexError is raised. The length should be equal to thenumber of values returned by the iterator.

Open issues: Other candidate methods, which can all havedefault concrete implementations that only depend on__len__and__getitem__ with an integer argument:__reversed__,index,count,__add__,__mul__.

MutableSequence
A subclass ofSequence adding some standard mutating methods.Abstract mutating methods:__setitem__ (for integer indices aswell as slices),__delitem__ (ditto),insert. Concretemutating methods:append,reverse,extend,pop,remove. Concrete mutating operators:+=,*= (thesemutate the object in place).Note: this does not definesort() – that is only required to exist on genuinelistinstances.

Strings

Python 3000 will likely have at least two built-in string types: bytestrings (bytes), deriving fromMutableSequence, and (Unicode)character strings (str), deriving fromSequence andHashable.

Open issues: define the base interfaces for these so alternativeimplementations and subclasses know what they are in for. This may bethe subject of a new PEP or PEPs (PEP 358 should be co-opted for thebytes type).

ABCs vs. Alternatives

In this section I will attempt to compare and contrast ABCs to otherapproaches that have been proposed.

ABCs vs. Duck Typing

Does the introduction of ABCs mean the end of Duck Typing? I don’tthink so. Python will not require that a class derives fromBasicMapping orSequence when it defines a__getitem__method, nor will thex[y] syntax require thatx is an instanceof either ABC. You will still be able to assign any “file-like”object tosys.stdout, as long as it has awrite method.

Of course, there will be some carrots to encourage users to derivefrom the appropriate base classes; these vary from defaultimplementations for certain functionality to an improved ability todistinguish between mappings and sequences. But there are no sticks.Ifhasattr(x,"__len__") works for you, great! ABCs are intended tosolve 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 ownGeneric Functions implementation[4] uses the classes (types) of thearguments as the dispatch key, allowing derived classes to overridebase classes. Since (from Python’s perspective) ABCs are quiteordinary classes, using an ABC in the default implementation for a GFcan be quite appropriate. For example, if I have an overloadedprettyprint function, it would make total sense to definepretty-printing of sets like this:

@prettyprint.register(Set)defpp_set(s):return"{"+...+"}"# Details left as an exercise

and implementations for specific subclasses of Set could be addedeasily.

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, orimplementation, classes) are all you need. But even they will notdeny the usefulness of inheritance; and one can easily consider theABCs proposed in this PEP as optional implementation base classes;there is no requirement that all user-defined mappings derive fromBasicMapping.

ABCs vs. Interfaces

ABCs are not intrinsically incompatible with Interfaces, but there isconsiderable overlap. For now, I’ll leave it to proponents ofInterfaces to explain why Interfaces are better. I expect that muchof the work that went into e.g. defining the various shades of“mapping-ness” and the nomenclature could easily be adapted for aproposal to use Interfaces instead of ABCs.

“Interfaces” in this context refers to a set of proposals foradditional metadata elements attached to a class which are not part ofthe regular class hierarchy, but do allow for certain types ofinheritance testing.

Such metadata would be designed, at least in some proposals, so as tobe easily mutable by an application, allowing application writers tooverride the normal classification of an object.

The drawback to this idea of attaching mutable metadata to a class isthat classes are shared state, and mutating them may lead to conflictsof intent. Additionally, the need to override the classification ofan object can be done more cleanly using generic functions: In thesimplest case, one can define a “category membership” generic functionthat simply returns False in the base implementation, and then provideoverrides that return True for any classes of interest.

References

[1]
An Introduction to ABC’s, by Talin(https://mail.python.org/pipermail/python-3000/2007-April/006614.html)

[2] Incomplete implementation prototype, by GvR (https://web.archive.org/web/20170223133820/http://svn.python.org/view/sandbox/trunk/abc/)

[3] Possible Python 3K Class Tree?, wiki page created by Bill Janssen (https://wiki.python.org/moin/AbstractBaseClasses)

[4]
Generic Functions implementation, by GvR(https://web.archive.org/web/20170223135019/http://svn.python.org/view/sandbox/trunk/overload/)
[5]
Charming Python: Scaling a new PEAK, by David Mertz(https://web.archive.org/web/20070515125102/http://www-128.ibm.com/developerworks/library/l-cppeak2/)
[6]
Implementation of @abstractmethod(https://github.com/python/cpython/issues/44895)
[7]
Unifying types and classes in Python 2.2, by GvR(https://www.python.org/download/releases/2.2.3/descrintro/)
[8]
Putting Metaclasses to Work: A New Dimension in Object-OrientedProgramming, by Ira R. Forman and Scott H. Danforth(https://archive.org/details/PuttingMetaclassesToWork)

[9] Partial order, in Wikipedia (https://en.wikipedia.org/wiki/Partial_order)

[10] Total order, in Wikipedia (https://en.wikipedia.org/wiki/Total_order)

[11]
Finite set, in Wikipedia(https://en.wikipedia.org/wiki/Finite_set)
[12]
Make isinstance/issubclass overloadable(https://bugs.python.org/issue1708353)
[13]
ABCMeta sample implementation(https://web.archive.org/web/20170224195724/http://svn.python.org/view/sandbox/trunk/abc/xyz.py)
[14]
python-dev email (“Comparing heterogeneous types”)https://mail.python.org/pipermail/python-dev/2004-June/045111.html
[15]
Functionfrozenset_hash() in Object/setobject.c(https://web.archive.org/web/20170224204758/http://svn.python.org/view/python/trunk/Objects/setobject.c)
[16]
Multiple interpreters in mod_python(https://web.archive.org/web/20070515132123/http://www.modpython.org/live/current/doc-html/pyapi-interps.html)

Copyright

This document has been placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-3119.rst

Last modified:2025-02-01 08:55:40 GMT


[8]ページ先頭

©2009-2025 Movatter.jp