Yet Another PEP: Interface Adapter Mechanism __adapt__
Clark C. Evans
cce at clarkevans.com
Wed Mar 21 22:04:42 EST 2001
On Wed, 21 Mar 2001, Rainer Deyke wrote:
> This 'check_base' stuff is a mess.
No joke. Sorry for being so brain dead. The following
code also has one or two errors, but should much better
illustrate the concept...
...
Here is the "merged" version where check_only is an
optional argument to adapt. Imagine the operator,
a isa b -> adapt(a,b,check_only=true)
--------------------------------------------------------
adapter/__init__.py
--------------------------------------------------------
import types
def adapt(obj,ident,check_only=0):
# check to see if the current object is ok as is
if obj is ident: return obj
if type(obj) is ident: return obj
if type(obj) is type(ident): return obj
if type(ident) is types.ClassType:
if type(obj) is types.InstanceType:
if isinstance(obj,ident): return obj
if type(obj) is types.ClassType:
if issubclass(obj,ident): return obj
# if we get a new interface type, code should
# be added in this spot to check if obj is an
# instance of ident, where ident is an types.Interface
# *THIS IS ANOTHER PEP*
# the obj may have the answer, so ask it about the ident
adapt = getattr(obj, '__adapt__',None)
if adapt:
retval = adapt(ident,check_only)
if retval: return retval
# the ident may have the answer, so ask it about the obj
# some code here for a class, type, or interface,
# or whatever to check to see if it can adapt the
# class. Unfortunately, calling __adapt__ won't
# work exactly here... we could add another
# argument, "forward"... *THIS IS ANOTHER PEP*
# a registry may exist, ask it about adapters.
# there may be a registry-based solution
# adapters that can be added to the system without
# modifying either A or B. *THIS IS ANOTHER PEP*
--------------------------------------------------------------
adapter/example.py
--------------------------------------------------------------
class EggsOnly: # an unrelated class/interface
def eggs(self,str): print "eggs!" + str
class HamOnly: # used as an interface, no inhertance
def ham(self,str): pass
def _bugger(self): pass # irritating a private member
class SpamOnly: # a base class, inheritance used
def spam(self,str): print "spam!" + str
class EggsSpamAndHam (SpamOnly):
def ham(self,str): print "ham!" + str
def __adapt__(self,ident,check_only):
if ident is HamOnly:
return self # implements HamOnly implicitly, no _bugger
if ident is EggsOnly and not check_only:
return EggsOnly() # Knows how to create the eggs!
------------------------------------------------------------------
testadapter.py
------------------------------------------------------------------
import adapter.example
from adapter import adapt
def testadapter():
x = adapter.example.EggsSpamAndHam()
adapt(x,adapter.example.SpamOnly).spam("Ni!")
adapt(x,adapter.example.EggsOnly).eggs("Ni!")
adapt(x,adapter.example.HamOnly).ham("Ni!")
adapt(x,adapter.example.EggsSpamAndHam).ham("Ni!")
#
# imagine operator syntax for check_only:
#
# if x isa adapter.example.SpamOnly: print "SpamOnly"
#
if (x,adapter.example.SpamOnly,1): print "SpamOnly"
if (x,adapter.example.EggsOnly,1): print "EggsOnly"
if (x,adapter.example.HamOnly,1): print "HamOnly"
if (x,adapter.example.EggsSpamAndHam,1): print "EggsAndSpam"
if (x,adapter.example.KnightsWhoSayNi,1): print "NightsWhoSayNi"
adapt(x,adapter.example.KnightsWhoSayNi,1).spam("Ni!")
--------------------------------------------------------------------
example run
--------------------------------------------------------------------
>>> import testadapter
>>> testadapter.testadapter()
spam!Ni!
eggs!Ni!
ham!Ni!
ham!Ni!
SpamOnly
EggsOnly
HamOnly
EggsAndSpam
Traceback (innermost last):
File "<interactive input>", line 1, in ?
File "c:\work\testadapter.py", line 13, in testadapter
if (x,adapter.example.KnightsWhoSayNi,1): print "NightsWhoSayNi"
AttributeError: KnightsWhoSayNi
More information about the Python-list
mailing list