Just in case anyone wants to play with a slightly more fleshed out, but still simple minded (in a good way) approach to adaption, I've put up an implementation here: http://members.cox.net/~tim.hochberg/adaption2.py It's adaption2, because I decided I didn't like my first try. No guarantees that it's not full of bugs, wrongheaded, etc, but it does give something concrete to look at.
It's quite similar to the Alex's super-simple proposal, with two main differences. 1. Protocols are indicated by Protocol objects, not strings. These objects just have a name, and no other features, so they aren't any more meaningful than strings, but by dint of being objects they can't collide. This also makes cancelling protocols a bit simpler. 2. The adaption is P->P, that is from one protocol to another protocol, rather than from T->P, that is from type to protocol. This makes things marginally more complicated since you need to associate types with protocols, but seems better for reasons I can't really articulate right now. As Alex suggested protocols are inherited by walking the mro for objects that have one. I'll include the module docstring below. Regards, -tim """adaption -- the worlds fourth most naive implementation of adaption Based on some post one python-dev-3000 on April 1st, 2006. Alex Martelli's being one of the main ones. Idiocies are all atributable to me (Tim Hochberg), however. The strategy is that objects have associated with them a set of protocols. These protocols are just tags that represent some interface or behaviour of the object. These tags are associated with the object by registering them using register_type. As an example, let's define a sequence type that starts it's indexing at 1: >>> class BaseOneSeq(object): ... def __init__(self, values): ... self._values = values ... def __getitem__(self, i): ... return self._values[i-1] We need a protocol to describe this class and we then need to register the class so the that the adaption machinery knows that the class and protocol are connected. >>> base1seq = Protocol("base1seq") >>> register_type(BaseOneSeq, base1seq) Now we want an adapter to adapt this to a normal sequence. >>> class BaseOneSeqToSeq(object): ... def __init__(self, target): ... self._target = target ... def __getitem__(self, i): ... return self._target[i+1] Finally, we need to register this adapter: >>> register_adapter(base1seq, protocols.sequence, BaseOneSeqToSeq) Phew. All done, now we can try it out: >>> b1 = BaseOneSeq([2,3,5,7,11,13,17,19,23]) >>> b1[1], b1[3], b1[5] (2, 5, 11) So far, so good. Now to adapt it to a normal, base-0 sequence: >>> seq = adapt(b1, protocols.sequence) >>> seq[0], seq[2], seq[4] (2, 5, 11) Well, that's cool, but it seemed like a lot of work. Now let's try out a cool, if possibly useless feature. AntiProtocols. This time, we repeat the same problem, but we derive from list to get __len__ and stuff for free: >>> class BaseOneSeq2(list): ... def __getitem__(self, i): ... return list.__getitem__(self, i-1) >>> register_type(BaseOneSeq2, base1seq) Notice that this time around is much easier -- we've already done a lot of the work. >>> b2 = BaseOneSeq2([2,3,5,7,11,13,17,19,23]) >>> b2[1], b2[3], b2[5] (2, 5, 11) >>> len(b2) 9 >>> seq2 = adapt(b2, protocols.sequence) >>> seq2[0], seq2[2], seq2[4] (23, 3, 7) Huh! The problem here is that we're inheriting from list and list is a sequence. If an object already satisfies a protocol, it gets returned from adapt unchanged. To fix that we need to nullify the sequence protocol that BaseOneSeq2 gets from list. AntiProtocols to the rescue: >>> register_type(BaseOneSeq2, ~protocols.sequence) >>> seq3 = adapt(b2, protocols.sequence) >>> seq3[0], seq3[2], seq3[4] (2, 5, 11) That's all folks. """ _______________________________________________ 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