2001-03-28 22:12:47 -05:00
|
|
|
|
PEP: 246
|
|
|
|
|
Title: Object Adaptation
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Author: cce@clarkevans.com (Clark C. Evans)
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Created: 21-Mar-2001
|
|
|
|
|
Python-Version: 2.2
|
2001-03-29 09:43:11 -05:00
|
|
|
|
Post-History: 29-Mar-2001
|
2001-03-28 22:12:47 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
|
|
|
|
|
This proposal puts forth an extensible mechanism for the
|
|
|
|
|
adaptation of an object to a context where a specific type, class,
|
|
|
|
|
interface, or other protocol is expected.
|
|
|
|
|
|
|
|
|
|
This proposal provides a built-in "adapt" function that, for any
|
|
|
|
|
object X and protocol Y, can be used to ask the Python environment
|
2002-02-04 16:09:10 -05:00
|
|
|
|
for a version of X compliant with Y. Behind the scenes, the
|
2001-03-28 22:12:47 -05:00
|
|
|
|
mechanism asks the object X: "Are you now, or do you know how to
|
|
|
|
|
wrap yourself to provide, a supporter of protocol Y?". And, if
|
|
|
|
|
this request fails, the function then asks the protocol Y: "Does
|
|
|
|
|
object X support you, or do you know how to wrap it to obtain such
|
|
|
|
|
a supporter?" This duality is important, because protocols can be
|
|
|
|
|
developed after objects are, or vice-versa, and this PEP lets
|
|
|
|
|
either case be supported non-invasively with regard to the
|
|
|
|
|
pre-existing component[s].
|
|
|
|
|
|
|
|
|
|
This proposal does not limit what a protocol is, what compliance
|
|
|
|
|
to the protocol means, nor what a wrapper constitutes. This
|
|
|
|
|
mechanism leverages existing protocol categories such as the type
|
|
|
|
|
system and class hierarchy and can be expanded to support future
|
|
|
|
|
protocol categories such as the pending interface proposal [1] and
|
|
|
|
|
signature based type-checking system [2].
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Motivation
|
|
|
|
|
|
|
|
|
|
Currently there is no standardized mechanism in Python for asking
|
|
|
|
|
if an object supports a particular protocol. Typically, existence
|
|
|
|
|
of particular methods, particularly those that are built-in such
|
|
|
|
|
as __getitem__, is used as an indicator of support for a
|
|
|
|
|
particular protocol. This technique works for protocols blessed
|
|
|
|
|
by the BDFL (Benevolent Dictator for Life), such as the new
|
|
|
|
|
enumerator proposal identified by a new built-in __iter__[9].
|
|
|
|
|
However, this technique does not admit an infallible way to
|
|
|
|
|
identify interfaces lacking a unique, built-in signature method.
|
|
|
|
|
|
|
|
|
|
More so, there is no standardized way to obtain an adapter for an
|
|
|
|
|
object. Typically, with objects passed to a context expecting a
|
|
|
|
|
particular protocol, either the object knows about the context and
|
|
|
|
|
provides its own wrapper or the context knows about the object and
|
|
|
|
|
wraps it appropriately. The difficulty with these approaches is
|
|
|
|
|
that such adaptations are one-offs, are not centralized in a
|
|
|
|
|
single place of the users code, and are not executed with a common
|
|
|
|
|
technique, etc. This lack of standardization increases code
|
|
|
|
|
duplication with the same adapter occurring in more than one place
|
|
|
|
|
or it encourages classes to be re-written instead of adapted. In
|
|
|
|
|
either case, maintainability suffers.
|
|
|
|
|
|
|
|
|
|
It would be very nice to have a standard function that can be
|
|
|
|
|
called upon to verify an object's compliance with a particular
|
|
|
|
|
protocol and provide for a wrapper if one is readily available --
|
|
|
|
|
all without having to hunt through a library's documentation for
|
|
|
|
|
the appropriate incantation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Requirements
|
|
|
|
|
|
|
|
|
|
When considering an objects compliance with a protocol, there are
|
|
|
|
|
several cases to be examined:
|
|
|
|
|
|
|
|
|
|
a) When the protocol is a type or class, and the object has
|
|
|
|
|
exactly that type or is a member of the class. In this case
|
|
|
|
|
compliance is automatic.
|
|
|
|
|
|
|
|
|
|
b) When the object knows about the protocol and either considers
|
|
|
|
|
itself compliant or knows how to wrap itself appropriately.
|
|
|
|
|
|
|
|
|
|
c) When the protocol knows about the object and either the object
|
|
|
|
|
already complies or can be wrapped accordingly.
|
|
|
|
|
|
|
|
|
|
d) When the protocol is a class, and the object is a member of a
|
|
|
|
|
subclass. This is distinct from the first case (a) above,
|
|
|
|
|
since inheritance does not necessarily imply substitutability
|
|
|
|
|
and must be handled carefully.
|
|
|
|
|
|
|
|
|
|
e) When the context knows about the object and the protocol and
|
|
|
|
|
knows how to adapt the object so that the required protocol is
|
|
|
|
|
satisfied. This could use an adapter registry or similar
|
|
|
|
|
method.
|
|
|
|
|
|
|
|
|
|
For this proposal's requirements, the first case should be come
|
|
|
|
|
for free and the next three cases should be relatively relatively
|
|
|
|
|
easy to accomplish. This proposal does not address the last case,
|
|
|
|
|
however it provides a base mechanism upon which such an approach
|
|
|
|
|
could be developed. Further, with only minor implementation
|
|
|
|
|
changes, this proposal should be able to incorporate a new
|
|
|
|
|
interface type or type checking system.
|
|
|
|
|
|
|
|
|
|
The fourth case above is subtle. A lack of substitutability can
|
|
|
|
|
occur when a method restricts an argument's domain or raises an
|
|
|
|
|
exception which a base class does not or extends the co-domain to
|
|
|
|
|
include return values which the base class may never produce.
|
|
|
|
|
While compliance based on class inheritance should be automatic,
|
|
|
|
|
this proposal should allow an object to signal that it is not
|
|
|
|
|
compliant with a base class protocol.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
|
|
|
|
|
This proposal introduces a new built-in function, adapt(), which
|
|
|
|
|
is the basis for supporting these requirements.
|
|
|
|
|
|
|
|
|
|
The adapt() function has three parameters:
|
|
|
|
|
|
|
|
|
|
- `obj', the object to be adapted
|
|
|
|
|
|
|
|
|
|
- `protocol', the protocol requested of the object
|
|
|
|
|
|
|
|
|
|
- `alternate', an optional object to return if the object could
|
|
|
|
|
not be adapted
|
|
|
|
|
|
|
|
|
|
A successful result of the adapt() function returns either the
|
|
|
|
|
object passed `obj' if the object is already compliant with the
|
|
|
|
|
protocol, or a secondary object `wrapper', which provides a view
|
|
|
|
|
of the object compliant with the protocol. The definition of
|
|
|
|
|
wrapper is explicitly vague and a wrapper is allowed to be a full
|
|
|
|
|
object with its own state if necessary. A failure to adapt the
|
|
|
|
|
object to the protocol will raise a TypeError unless the alternate
|
|
|
|
|
parameter is used, in this case the alternate argument is
|
|
|
|
|
returned.
|
|
|
|
|
|
|
|
|
|
To enable the first case listed in the requirements, the adapt()
|
|
|
|
|
function first checks to see if the object's type or the object's
|
|
|
|
|
class are identical to the protocol. If so, then the adapt()
|
|
|
|
|
function returns the object directly without further ado.
|
|
|
|
|
|
|
|
|
|
To enable the second case, when the object knows about the
|
|
|
|
|
protocol, the object must have a __conform__() method. This
|
|
|
|
|
optional method takes two arguments:
|
|
|
|
|
|
|
|
|
|
- `self', the object being conformed
|
|
|
|
|
|
|
|
|
|
- `protocol, the protocol requested
|
|
|
|
|
|
|
|
|
|
The object may return itself through this method to indicate
|
|
|
|
|
compliance. Alternatively, the object also has the option of
|
|
|
|
|
returning a wrapper object compliant with the protocol. Finally,
|
|
|
|
|
if the object cannot determine its compliance, it should either
|
|
|
|
|
return None or raise a TypeError to enable the remaining
|
|
|
|
|
mechanisms.
|
|
|
|
|
|
|
|
|
|
To enable the third case, when the protocol knows about the
|
|
|
|
|
object, the protocol must have an __adapt__() method. This
|
|
|
|
|
optional method takes two arguments:
|
|
|
|
|
|
|
|
|
|
- `self', the protocol requested
|
|
|
|
|
|
|
|
|
|
- `obj', the object being adapted
|
|
|
|
|
|
|
|
|
|
If the protocol finds the object to be compliant, it can return
|
|
|
|
|
obj directly. Alternatively, the method may return a wrapper
|
|
|
|
|
compliant with the protocol. Finally, compliance cannot be
|
|
|
|
|
determined, this method should either return None or raise a
|
|
|
|
|
TypeError so other mechanisms can be tried.
|
|
|
|
|
|
|
|
|
|
The fourth case, when the object's class is a sub-class of the
|
|
|
|
|
protocol, is handled by the built-in adapt() function. Under
|
|
|
|
|
normal circumstances, if "isinstance(object, protocol)" then
|
|
|
|
|
adapt() returns the object directly. However, if the object is
|
|
|
|
|
not substitutable, either the __conform__() or __adapt__() methods
|
|
|
|
|
above may raise an adaptForceFailException to prevent this default
|
|
|
|
|
behavior.
|
|
|
|
|
|
|
|
|
|
Please note two important things. First, this proposal does not
|
|
|
|
|
preclude the addition of other protocols. Second, this proposal
|
|
|
|
|
does not preclude other possible cases where adapter pattern may
|
|
|
|
|
hold, such as the context knowing the object and the protocol (the
|
|
|
|
|
last case in the requirements). In fact, this proposal opens the
|
|
|
|
|
gate for these other mechanisms to be added.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Reference Implementation and Test Cases
|
|
|
|
|
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
adapt.py
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
import types
|
|
|
|
|
|
|
|
|
|
adaptRaiseTypeException = "(raise a type exception on failure)"
|
|
|
|
|
adaptForceFailException = "(forced failure of adapt)"
|
|
|
|
|
|
|
|
|
|
# look to see if the object passes other protocols
|
|
|
|
|
def _check(obj,protocol,default):
|
|
|
|
|
return default
|
|
|
|
|
|
|
|
|
|
def adapt(obj, protocol, alternate = adaptRaiseTypeException):
|
|
|
|
|
|
|
|
|
|
# first check to see if object has the exact protocol
|
|
|
|
|
if type(obj) is types.InstanceType and \
|
|
|
|
|
obj.__class__ is protocol: return obj
|
|
|
|
|
if type(obj) is protocol: return obj
|
|
|
|
|
|
|
|
|
|
# next check other protocols for exact conformance
|
|
|
|
|
# before calling __conform__ or __adapt__
|
|
|
|
|
if _check(obj,protocol,0):
|
|
|
|
|
return obj
|
|
|
|
|
|
|
|
|
|
# procedure to execute on success
|
|
|
|
|
def succeed(obj,retval,protocol,alternate):
|
|
|
|
|
if _check(retval,protocol,1):
|
|
|
|
|
return retval
|
|
|
|
|
else:
|
|
|
|
|
return fail(obj,alternate)
|
|
|
|
|
|
|
|
|
|
# procedure to execute on failure
|
|
|
|
|
def fail(obj,protocol,alternate):
|
|
|
|
|
if alternate is adaptRaiseTypeException:
|
|
|
|
|
raise TypeError("%s cannot be adapted to %s" \
|
|
|
|
|
% (obj,protocol))
|
|
|
|
|
return alternate
|
|
|
|
|
|
|
|
|
|
# try to use the object's adapting mechanism
|
|
|
|
|
conform = getattr(obj, '__conform__',None)
|
|
|
|
|
if conform:
|
|
|
|
|
try:
|
|
|
|
|
retval = conform(protocol)
|
|
|
|
|
if retval:
|
|
|
|
|
return succeed(obj,retval,protocol,alternate)
|
|
|
|
|
except adaptForceFailException:
|
|
|
|
|
return fail(obj,protocol,alternate)
|
|
|
|
|
except TypeError: pass
|
|
|
|
|
|
|
|
|
|
# try to use the protocol's adapting mechanism
|
|
|
|
|
adapt = getattr(protocol, '__adapt__',None)
|
|
|
|
|
if adapt:
|
|
|
|
|
try:
|
|
|
|
|
retval = adapt(obj)
|
|
|
|
|
if retval:
|
|
|
|
|
return succeed(obj,retval,protocol,alternate)
|
|
|
|
|
except adaptForceFailException:
|
|
|
|
|
return fail(obj,protocol,alternate)
|
|
|
|
|
except TypeError: pass
|
|
|
|
|
|
|
|
|
|
# check to see if the object is an instance
|
|
|
|
|
try:
|
|
|
|
|
if isinstance(obj,protocol):
|
|
|
|
|
return obj
|
|
|
|
|
except TypeError: pass
|
|
|
|
|
|
|
|
|
|
# no-adaptation-possible case
|
|
|
|
|
return fail(obj,protocol,alternate)
|
|
|
|
|
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
test.py
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
import types
|
|
|
|
|
from adapt import adaptForceFailException
|
|
|
|
|
from adapt import adapt
|
|
|
|
|
|
|
|
|
|
class KnightsWhoSayNi: pass
|
|
|
|
|
|
|
|
|
|
class Eggs: # an unrelated class/interface
|
|
|
|
|
def eggs(self): print "eggs!"
|
|
|
|
|
word = "Nee-womm"
|
|
|
|
|
|
|
|
|
|
class Ham: # used as an interface, no inhertance
|
|
|
|
|
def ham(self): pass
|
|
|
|
|
word = "Ping"
|
|
|
|
|
|
|
|
|
|
class Spam: # a base class, inheritance used
|
|
|
|
|
def spam(self): print "spam!"
|
|
|
|
|
|
|
|
|
|
class EggsSpamAndHam (Spam,KnightsWhoSayNi):
|
|
|
|
|
def ham(self): print "ham!"
|
|
|
|
|
def __conform__(self,protocol):
|
|
|
|
|
if protocol is Ham:
|
|
|
|
|
# implements Ham's ham, but does not have a word
|
|
|
|
|
return self
|
|
|
|
|
if protocol is KnightsWhoSayNi:
|
|
|
|
|
# we are no longer the Knights who say Ni!
|
|
|
|
|
raise adaptForceFailException
|
|
|
|
|
if protocol is Eggs:
|
|
|
|
|
# Knows how to create the eggs!
|
|
|
|
|
return Eggs()
|
|
|
|
|
|
|
|
|
|
class SacredWord:
|
|
|
|
|
class HasSecredWord:
|
|
|
|
|
def __call__(self, obj):
|
|
|
|
|
if getattr(obj,'word',None): return obj
|
|
|
|
|
__adapt__= HasSecredWord()
|
|
|
|
|
|
|
|
|
|
class Bing (Ham):
|
|
|
|
|
def __conform__(self,protocol):
|
|
|
|
|
raise adaptForceFailException
|
|
|
|
|
|
|
|
|
|
def test():
|
|
|
|
|
x = EggsSpamAndHam()
|
|
|
|
|
adapt(x,Spam).spam()
|
|
|
|
|
adapt(x,Eggs).eggs()
|
|
|
|
|
adapt(x,Ham).ham()
|
|
|
|
|
adapt(x,EggsSpamAndHam).ham()
|
|
|
|
|
print adapt(Eggs(),SacredWord).word
|
|
|
|
|
print adapt(Ham(),SacredWord).word
|
|
|
|
|
pass
|
|
|
|
|
if adapt(x,KnightsWhoSayNi,None): raise "IckyIcky"
|
|
|
|
|
if not adapt(x,Spam,None): raise "Spam"
|
|
|
|
|
if not adapt(x,Eggs,None): raise "Eggs"
|
|
|
|
|
if not adapt(x,Ham,None): raise "Ham"
|
|
|
|
|
if not adapt(x,EggsSpamAndHam,None): raise "EggsAndSpam"
|
|
|
|
|
if adapt(x,KnightsWhoSayNi,None): raise "NightsWhoSayNi"
|
|
|
|
|
if adapt(x,SacredWord,None): raise "SacredWord"
|
|
|
|
|
try:
|
|
|
|
|
adapt(x,SacredWord)
|
|
|
|
|
except TypeError: pass
|
|
|
|
|
else: raise "SacredWord"
|
|
|
|
|
try:
|
|
|
|
|
adapt(x,KnightsWhoSayNi)
|
|
|
|
|
except TypeError: print "Ekky-ekky-ekky-ekky-z'Bang, " \
|
|
|
|
|
+ "zoom-Boing, z'nourrrwringmm"
|
|
|
|
|
else: raise "NightsWhoSayNi"
|
|
|
|
|
pass
|
|
|
|
|
b = Bing()
|
|
|
|
|
if not adapt(b,Bing,None): raise "Not a Bing"
|
|
|
|
|
if adapt(b,Ham,None): raise "Not a Ham!"
|
|
|
|
|
if adapt(1,types.FloatType,None): raise "Not a float!"
|
|
|
|
|
if adapt(b,types.FloatType,None): raise "Not a float!"
|
|
|
|
|
if adapt(1,Ham,None): raise "Not a Ham!"
|
|
|
|
|
if not adapt(1,types.IntType,None): raise "Is an Int!"
|
|
|
|
|
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
Expected Output
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
>>> import test
|
|
|
|
|
>>> test.test()
|
|
|
|
|
spam!
|
|
|
|
|
eggs!
|
|
|
|
|
ham!
|
|
|
|
|
ham!
|
|
|
|
|
Nee-womm
|
|
|
|
|
Ping
|
|
|
|
|
Ekky-ekky-ekky-ekky-z'Bang, zoom-Boing, z'nourrrwringmm
|
|
|
|
|
>>>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Relationship To Paul Prescod and Tim Hochberg's Type Assertion method
|
|
|
|
|
|
|
|
|
|
Paul and Tim had proposed a type checking mechanism, where the
|
|
|
|
|
Interface is passed an object to verify. The example syntax Paul
|
|
|
|
|
put forth recently [2] was:
|
|
|
|
|
|
|
|
|
|
interface Interface
|
|
|
|
|
def __check__(self,obj)
|
|
|
|
|
|
|
|
|
|
For discussion purposes, here would be a protocol with __check__:
|
|
|
|
|
|
|
|
|
|
class Interface:
|
|
|
|
|
class Checker:
|
|
|
|
|
def __call__(self, obj): pass #check the object
|
|
|
|
|
__check__= Checker()
|
|
|
|
|
|
|
|
|
|
The built-in adapt() function could be augmented to use this
|
|
|
|
|
checking mechanism updating the _check method as follows:
|
|
|
|
|
|
|
|
|
|
# look to see if the object passes other protocols
|
|
|
|
|
def _check(obj,protocol,default):
|
|
|
|
|
check = getattr(protocol, '__check__',None)
|
|
|
|
|
if check:
|
|
|
|
|
try:
|
|
|
|
|
if check(obj): return 1
|
|
|
|
|
except TypeError: pass
|
|
|
|
|
return 0
|
|
|
|
|
else:
|
|
|
|
|
return default
|
|
|
|
|
|
|
|
|
|
In short, the work put forth by Paul and company is great, and
|
|
|
|
|
there should be no problem preventing these two proposals from
|
|
|
|
|
working together in harmony, if not be completely complementary.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Relationship to Python Interfaces [1] by Michel Pelletier
|
|
|
|
|
|
|
|
|
|
The relationship to this proposal to Michel's proposal could also
|
|
|
|
|
be complementary. Following is how the _check method would be
|
|
|
|
|
updated for this mechanism:
|
|
|
|
|
|
|
|
|
|
# look to see if the object passes other protocols
|
|
|
|
|
def _check(obj,protocol,default):
|
|
|
|
|
if type(protocol) is types.InterfaceType:
|
|
|
|
|
return implements(obj,protocol)
|
|
|
|
|
return default
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Relationship to Carlos Ribeiro's proxy technique [7] and [8]
|
|
|
|
|
|
|
|
|
|
Carlos presented a technique where this method could return a
|
|
|
|
|
proxy instead of self or a wrapper. The advantage of this
|
|
|
|
|
approach is that the internal details of the object are protected.
|
|
|
|
|
This is very neat. No changes are necessary to this proposal to
|
|
|
|
|
support this usage as a standardized mechanism to obtain named
|
|
|
|
|
proxies.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Relationship To Microsoft's Query Interface
|
|
|
|
|
|
|
|
|
|
Although this proposal may sounds similar to Microsoft's
|
|
|
|
|
QueryInterface, it differs by a number of aspects.
|
|
|
|
|
|
|
|
|
|
First, it is bi-directional allowing the interface to be queried
|
|
|
|
|
as well giving more dynamic abilities (more Pythonic). Second,
|
|
|
|
|
there is not a special "IUnknown" interface which can be used for
|
|
|
|
|
object identity, although this could be proposed as one of those
|
|
|
|
|
"special" blessed interface protocol identifiers. Third, with
|
|
|
|
|
QueryInterface, once an object supports a particular interface it
|
|
|
|
|
must always there after support this interface; this proposal
|
|
|
|
|
makes no such guarantee, although this may be added at a later
|
|
|
|
|
time. Fourth, implementations of Microsoft's QueryInterface must
|
|
|
|
|
support a kind of equivalence relation.
|
|
|
|
|
|
|
|
|
|
By reflexive they mean the querying an interface for itself must
|
|
|
|
|
always succeed. By symmetrical they mean that if one can
|
|
|
|
|
successfully query an interface IA for a second interface IB, then
|
|
|
|
|
one must also be able to successfully query the interface IB for
|
|
|
|
|
IA. And finally, by transitive they mean if one can successfully
|
|
|
|
|
query IA for IB and one can successfully query IB for IC, then one
|
|
|
|
|
must be able to successfully query IA for IC. Ability to support
|
|
|
|
|
this type of equivalence relation should be encouraged, but may
|
|
|
|
|
not be possible. Further research on this topic (by someone
|
|
|
|
|
familiar with Microsoft COM) would be helpful in further
|
|
|
|
|
determining how compatible this proposal is.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Question and Answer
|
|
|
|
|
|
|
|
|
|
Q: What benefit does this provide?
|
|
|
|
|
|
|
|
|
|
The typical Python programmer is an integrator, someone who is
|
|
|
|
|
connecting components from various vendors. Often times the
|
|
|
|
|
interfaces between these components require an intermediate
|
|
|
|
|
adapter. Usually the burden falls upon the programmer to
|
|
|
|
|
study the interface exposed by one component and required by
|
|
|
|
|
another, determine if they are directly compatible, or develop
|
|
|
|
|
an adapter. Sometimes a vendor may even include the
|
|
|
|
|
appropriate adapter, but then searching for the adapter and
|
|
|
|
|
figuring out how to deploy the adapter takes time.
|
|
|
|
|
|
|
|
|
|
This technique enables vendors to work with each other
|
|
|
|
|
directly by implementing __conform__ or __adapt__ as
|
|
|
|
|
necessary. This frees the integrator from making their own
|
|
|
|
|
adapters. In essence, this allows the components to have a
|
|
|
|
|
simple dialogue among themselves. The integrator simply
|
|
|
|
|
connects one component to another, and if the types don't
|
|
|
|
|
automatically match an adapting mechanism is built-in.
|
|
|
|
|
|
|
|
|
|
For example, consider SAX1 and SAX2 interfaces, there is an
|
|
|
|
|
adapter required to switch between them. Normally the
|
|
|
|
|
programmer must be aware of this; however, with this
|
|
|
|
|
adaptation framework this is no longer the case.
|
|
|
|
|
|
|
|
|
|
Q: Why does this have to be built-in, can't it be standalone?
|
|
|
|
|
|
|
|
|
|
Yes, it does work standalone. However, if it is built-in, it
|
|
|
|
|
has a greater chance of usage. The value of this proposal is
|
|
|
|
|
primarily in standardization. Furthermore:
|
|
|
|
|
|
|
|
|
|
0. The mechanism is by its very nature a singleton.
|
|
|
|
|
|
|
|
|
|
1. If used frequently, it will be much faster as a built-in
|
|
|
|
|
|
|
|
|
|
2. It is extensible and unassuming.
|
|
|
|
|
|
|
|
|
|
3. A whole-program optimizing compiler could optimize it out
|
|
|
|
|
in particular cases (ok, this one is far fetched)
|
|
|
|
|
|
|
|
|
|
Q: Why the verbs __conform__ and __adapt__?
|
|
|
|
|
|
|
|
|
|
conform, verb intransitive
|
|
|
|
|
1. To correspond in form or character; be similar.
|
|
|
|
|
2. To act or be in accord or agreement; comply.
|
|
|
|
|
3. To act in accordance with current customs or modes.
|
|
|
|
|
|
|
|
|
|
adapt, verb transitive
|
|
|
|
|
1. To make suitable to or fit for a specific use or
|
|
|
|
|
situation.
|
|
|
|
|
|
|
|
|
|
Source: The American Heritage Dictionary of the English
|
|
|
|
|
Language, Third Edition
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Backwards Compatibility
|
|
|
|
|
|
|
|
|
|
There should be no problem with backwards compatibility unless
|
|
|
|
|
someone had used __conform__ or __adapt__, but this seems
|
|
|
|
|
unlikely. Indeed this proposal, save an built-in adapt()
|
|
|
|
|
function, could be tested without changes to the interpreter.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Credits
|
|
|
|
|
|
|
|
|
|
This proposal was created in large part by the feedback of the
|
|
|
|
|
talented individuals on both the main mailing list and also the
|
|
|
|
|
type-sig list. Specific contributors include (sorry if I missed
|
|
|
|
|
someone).
|
|
|
|
|
|
|
|
|
|
This proposal is based largely off the suggestions from Alex
|
|
|
|
|
Martelli and Paul Prescod with significant feedback from Robin
|
|
|
|
|
Thomas and borrowing ideas from Marcin 'Qrczak' Kowalczyk and
|
|
|
|
|
Carlos Ribeiro. Other contributors (via comments) include Michel
|
|
|
|
|
Pelletier, Jeremy Hylton, Aahz Maruch, Fredrik Lundh, Rainer
|
|
|
|
|
Deyke, Timothy Delaney, and Huaiyu Zhu
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References and Footnotes
|
|
|
|
|
|
|
|
|
|
[1] PEP 245, Python Interface Syntax, Pelletier
|
|
|
|
|
http://www.python.org/peps/pep-0245.html
|
|
|
|
|
|
|
|
|
|
[2] http://mail.python.org/pipermail/types-sig/2001-March/001223.html
|
|
|
|
|
|
|
|
|
|
[3] http://www.zope.org/Members/michel/types-sig/TreasureTrove
|
|
|
|
|
|
|
|
|
|
[4] http://mail.python.org/pipermail/types-sig/2001-March/001105.html
|
|
|
|
|
|
|
|
|
|
[5] http://mail.python.org/pipermail/types-sig/2001-March/001206.html
|
|
|
|
|
|
|
|
|
|
[6] http://mail.python.org/pipermail/types-sig/2001-March/001223.html
|
|
|
|
|
|
|
|
|
|
[7] http://mail.python.org/pipermail/python-list/2001-March/035136.html
|
|
|
|
|
|
|
|
|
|
[8] http://mail.python.org/pipermail/python-list/2001-March/035197.html
|
|
|
|
|
|
2001-07-05 15:20:16 -04:00
|
|
|
|
[9] PEP 234, Iterators, Yee, Van Rossum
|
2001-03-28 22:12:47 -05:00
|
|
|
|
http://www.python.org/peps/pep-0234.txt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
End:
|