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

Guido van Rossum guido at python.org
Fri Apr 7 19:36:17 CEST 2006


On 4/5/06, Walter Dörwald <walter at livinglogic.de> wrote:
> 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.

Using @overloaded functions I would create an explicit class variable
which is the @overloaded adapter rather than trying to make the
interface also *be* the adapter. I would define the Interface class
like this:

class InterfaceMetaclass(type):
    # I hate anonymous metaclasses
    def __new__(mcl, name, bases, dict):
        # Give each class it's own registry
        dict["adapter"] = overloaded(None)  # set default_function to None
        return type.__new__(mcl, name, bases, dict)

class Interface:
    __metaclass__ = InterfaceMetaclass
    # No need for adapt and register methods here

The registration would then look like this:

Sequence.adapter.register(list)(PythonSeqAsSequence)

and the invocation would look like this:

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

--
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list