[Types-sig] QueryProtocol

Clark C. Evans cce@clarkevans.com
Wed, 21 Mar 2001 18:24:14 -0500 (EST)


On Wed, 21 Mar 2001, Clark C. Evans wrote:
> However, "adapt" could easly call "check" for the trivial 
> case, or the functions could be merged with an argument
> (checkonly=true/false). 

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

    # 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"...  

--------------------------------------------------------------
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