[Python-3000] Adaptation vs. Generic Functions

Walter Dörwald walter at livinglogic.de
Thu Apr 6 07:46:14 CEST 2006


Guido van Rossum wrote:

> On 4/5/06, Walter Dörwald <walter at livinglogic.de> wrote:
>> The problem with this is that it looks in the base protocol only if the
>> the class can't be found in the registry of the subprotocol. This mean
>> that an adapter from the subprotocol might be used, although the base
>> protocol has a "better" adapter (i.e. one whose class that is nearer to
>> real class of the object.
> 
> It also doesn't look like it will work right for recursive invocations
> of the adapter by some implementation (as happens to be common for the
> pprint example).

If the protocol was a class instead of an instance we could use the mro 
of the protocol:

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, *types):
         def decorator(adapter):
             for type in types:
                 cls.registry[type] = adapter
         return decorator

     def default(cls, *args, **kwargs):
         raise TypeError("can adapt %r to %r" % (args[0], cls))

     def __call__(cls, *args, **kwargs):
         # Cannot construct protocol instances
         # Instead, calling the class triggers adaptation
         for basetype in type(args[0]).__mro__:
             for baseprotocol in cls.__mro__:
                 registry = getattr(baseprotocol, "registry", None)
                 if registry is not None:
                     adapter = registry.get(basetype)
                     if adapter is not None:
                         # Must pass the protocol to the adapter
                         # so that it can dispath to the right protocol
                         return adapter(cls, *args, **kwargs)
         return cls.default(*args, **kwargs)

class Protocol(object):
      __metaclass__ = MetaInterface

# Extensible repr protocol
class xrepr(Protocol):
     @classmethod
     def default(cls, *args, **kwargs):
         return repr(*args, **kwargs)

@xrepr.register(list)
def xrepr_list(protocol, obj):
     return "[%s]" % ", ".join(protocol(x) for x in obj)

# Subprotocol that overwrites int/long adaption

class hexrepr(xrepr):
     pass

@hexrepr.register(int, long)
def hexrepr_number(protocol, obj):
     return  hex(obj)

print hexrepr(range(4))

This prints

[0x0, 0x1, 0x2, 0x3]

Servus,
    Walter


More information about the Python-3000 mailing list