PEP 318

Andrew Bennetts andrew-pythonlist at puzzling.org
Wed Mar 24 01:00:57 EST 2004


On Tue, Mar 23, 2004 at 09:04:44PM -0800, Michele Simionato wrote:
> Skip Montanaro <skip at pobox.com> wrote in message news:<mailman.289.1080056808.742.python-list at python.org>...
> > 
> > Okay, but can you explain the mechanism or point me to the original post?  I
> > can't find it on Google (probably too recent).  Multimethod(a,b)() won't
> > know that each call is for __mul__ will it (maybe it will peek at the
> > func_name attribute)?  From what you posted, all I saw was multiple
> > definitions of __mul__.  Only the last one will be present as a method in
> > the class's definition.
> > 
> > Skip
> 
> Please take what I posted just as an idea (it is not even my idea!), not as 
> an implementation proposal.
> I don't have an implementation, but I am pretty much convinced that it is
> possible and not that hard. 
> I am not suggesting that we put multimethods in Python 2.4. 
> I am just noticing that the notation could be used to denote 
> multimethods too, as Ville Vainio suggested (sorry for the mispelling,
> Ville!).
> 
> Just to support your point that the decorator idea is a Pandora box, and 
> we can extract anything from it ;)

But the decorator syntax doesn't help with this case at all.

You *could* hack up multimethods today, though, by abusing metaclasses:

class Foo:
    ...
    class __mul__(multimethod):
        def Matrix(self, other):
            ...
        def Vector(self, other):
            ...

The definition of multimethod would be something like this:

class _multimethod(type):
    def __new__(cls, name, bases, d):
        if d.get('__metaclass__') == _multimethod:
            return super(_multimethod, cls).__new__(cls, name, bases, d)
        else:
            def multi(self, *args):
                try:
                    meth = d['_'.join([arg.__class__.__name__ for arg in args])]
                except KeyError:
                    raise TypeError, 'No multimethod for type(s) %r' % map(type, args)
                else:
                    return meth(self, *args)
            return multi

class multimethod:
    __metaclass__ = _multimethod

This is only very lightly tested.  Extending this to cope with subclasses of
types, etc, is left as an exercise for the reader.

FWIW, here is what I tested it with:

if __name__ == '__main__':
    class C:
        class __mul__(multimethod):
            def int(self, other):
                return 'Integer multipication!'
            def C(self, other):
                return 'Selfness squared!'

        class test(multimethod):
            def int_str(self, i, s):
                return 'Testing %r, %r' % (i, s)
    c = C()
    print c * 1
    print c * c
    try:
        print c * "x"
    except TypeError, e:
        print e.args[0]

    print c.test(2, 'two')
    try:
        print c.test('x', 'y')
    except TypeError, e:
        print e.args[0]

-Andrew.





More information about the Python-list mailing list