[Python-3000] Adaption & generic functions [was Generic functions]
Walter Dörwald
walter at livinglogic.de
Wed Apr 5 09:43:04 CEST 2006
Guido van Rossum wrote:
> On 4/4/06, Tim Hochberg <tim.hochberg at cox.net> wrote:
> [...]
>> def __init__(self, name, doc=''):
>> self.name = name
>> self.registry = {}
>> self.__doc__ = doc
>> self.all_protocols.add(self)
>> def __repr__(self):
>> return "<protocol %r>" % self.name
>> __str__ = __repr__
>> def __call__(self, *args):
>> for key in self.keysof(*args):
>> adapter = self.registry.get(key, None)
>> if adapter is not None:
>> return adapter(*args)
>> raise ValueError('adapter not found')
>
> So __call__ is what used to be call adapt. Or, rather, where Alex used
> to write adapt(x, P) and where I write P.adapt(x), you just write P().
> Clever.
I've used that in my example too (see
http://mail.python.org/pipermail/python-3000/2006-April/000308.html)
But might closes off one route we could take if we're adapting to
something that must provide more than one function/method (i.e. an
interface) and we'd like to have the interface and the adaption registry
be identical. Suppose we're designing a new interface for sequence. A
sequence must provide getitem() and len() methods. If the adapt(at)ion
API only used register and adapt methods we could do something like this:
class Interface(object):
class __metaclass__(type):
def __new__(mcl, name, bases, dict):
# Give each class it's own registry
dict["registry"] = {}
return type.__new__(mcl, name, bases, dict)
@classmethod
def register(cls, adapter, T):
cls.registry[T] = adapter
@classmethod
def adapt(cls, obj):
for base in type(obj).__mro__:
try:
return cls.registry[base](obj)
except KeyError:
pass
raise TypeError("can't adapt %r to %r" % (obj, cls))
class Sequence(Interface):
def getitem(self, index): pass
def len(self): pass
class PythonSeqAsSequence(Sequence):
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.adapt([1,2,3]).len()
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.
Bye,
Walter Dörwald
More information about the Python-3000
mailing list