[Python-3000] Adaption & generic functions [was Generic functions]

Nick Coghlan ncoghlan at gmail.com
Wed Apr 5 11:35:03 CEST 2006


Walter Dörwald wrote:
> But if adapting is done via __call__() we have a problem: Sequence 
> already provides a __call__, the constructor. Of course if this worked
> 
> print Sequence([1,2,3]).len()
> 
> would look much better than
> 
> print Sequence.adapt([1,2,3]).len()
> 
> but I'm not sure if it's possible to work around the constructor/adapt 
> clash.

You can redefine __call__ in the metaclass to fix it:

Py> class ClassCall:
...     class __metaclass__(type):
...         def __call__(cls):
...             print "Calling", cls
...
Py> ClassCall()
Calling <class '__main__.ClassCall'>

So your example would become:

class MetaInterface(type):
     def __new__(mcl, name, bases, dict):
         # Give each class it's own registry
         cls = type.__new__(mcl, name, bases, dict)
         cls.registry = {}
         return cls

     def register(cls, adapter, T):
         cls.registry[T] = adapter

     def register_for(cls, T):
         # Registration decorator
         def register_func(adapter):
             cls.register(adapter, T)
         return register_func

     def __call__(cls, obj):
         # Cannot construct interface instances
         # Instead, calling the class triggers adaptation
         for base in type(obj).__mro__:
             try:
                 adapter = cls.registry[base]
             except KeyError:
                 pass
             if adapter is None:
                 return obj
             return adapter(obj)
         raise TypeError("can't adapt %r to %r" % (obj, cls))

class Interface(object):
     __metaclass__ = MetaInterface

class Sequence(Interface):
     def getitem(self, index): pass
     def len(self): pass


class PythonSeqAsSequence(object): # Adapter is a normal class!
     def __init__(self, obj):
        self.obj = obj

     def getitem(self, index):
        return self.obj[i]

     def len(self):
        return len(self.obj)

Sequence.register(PythonSeqAsSequence, list)

print Sequence([1,2,3]).len()

# Or using the function decorator version
@Sequence.register_for(tuple)
def tuple_as_seq(obj):
     class AdaptedTuple(object):
         def getitem(self, index):
             return obj[i]
         def len(self):
             return len(obj)
     return AdaptedTuple()

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-3000 mailing list