Trapping numeric operators

John Dell'Aquila dellaq at ml1.net
Thu Oct 21 22:52:06 EDT 2004


I want to trap numeric operators (+ * % etc.) so that my new style
classes can handle them generically, similar to __getattr__ in an old
style class.

I've never done any metaprogramming before but I'm thinking of using
the below metaclass to accomplish this. It reads a class variable,
implements_operators, to determine which methods handle various
operators, then inserts closures to call the generic methods with
disambiguating parameters (the name of the magic method and the
corresponding operator built-in, if it can be determined).

Is this a reasonable approach or an abuse of metaclasses? Any comments
would be deeply appreciated.

Thanks,
John

import operator   # the metaclass
class metaOperator(type):
    def __new__(cls, classname, bases, classdict):
        fnDict = classdict['implements_operators']
        for fn in fnDict.iterkeys():
            for magicName in fnDict[fn]:
                for opName in (magicName, '__%s'%magicName[3:]):
                    # try magicName else assume in-place/right
                    # and strip out the presumptive 'i'/'r'
                    try:
                        op = getattr(operator, opName)
                        break
                    except AttributeError:
                        pass
                else:
                    op = None
                classdict[magicName] = (
                    lambda self, other=None, name=magicName, op=op, fn=fn:
                    fn(self, other, name, op)
                    )
        return type.__new__(cls, classname, bases, classdict)

class Q(object):  # a sketch of its use
    __metaclass__ = metaOperator

    def binop(self, other, name, op): pass
    def ibinop(self, other, name, op): pass
    def unop(self, other, name, op): pass

    implements_operators = {
        binop: ('__add__','__sub__','__mul__','__div__'),
        ibinop: ('__iadd__','__isub__','__imul__','__idiv__'),
        unop: ('__neg__','__pos__','__abs__','__invert__'),
        }



More information about the Python-list mailing list