Guido van Rossum wrote: > On 4/5/06, Walter Dörwald <[EMAIL PROTECTED]> 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()
This looks reasonable enough, as the adapter comes for free and it avoids the problem of a __call__() in the Interface or its metaclass. But if I'm implementing an adapter for a certain type, I still can't make the returned object an instance of Interface (or I could, but it would inherit an adapter, which is useless), so I would have: class Interface: def getitem(self, index): ... def len(self, index): ... Interface.adapter() which I have to call to do the adaption and class PythonSeqAsSequence: def getitem(self, index): ... def len(self, index): ... which implements the Sequence protocol, but shouldn't subclass Sequence. Somehow this feels awkward to me. Servus, Walter _______________________________________________ Python-3000 mailing list Python-3000@python.org http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com