python: generalizing delegating a method
Question: I have a class like this containing one or more numeric elements.

    
    
    class Foo:
        # ... other methods ...
        def _update(self, f):
            # ... returns a new Foo() object based on transforming
            #     one or more data members with a function f()
        def __add__(self, k):
            return self._update(lambda x: x.__add__(k))
        def __radd__(self, k):
            return self._update(lambda x: x.__radd__(k))
        def __sub__(self, k):
            return self._update(lambda x: x.__sub__(k))
        def __rsub__(self, k):
            return self._update(lambda x: x.__rsub__(k))
        def __mul__(self, k):
            return self._update(lambda x: x.__mul__(k))
        def __rmul__(self, k):
            return self._update(lambda x: x.__rmul__(k))
        def __div__(self, k):
            return self._update(lambda x: x.__div__(k))
        def __rdiv__(self, k):
            return self._update(lambda x: x.__rdiv__(k))
        # I want to add other numeric methods also
    

Is there any way to generalize this for all the [numeric
methods](http://docs.python.org/2/reference/datamodel.html#numeric-types),
without having to do this for each and every one of them?

I just want to delegate for any method in the list of numeric methods.


Answer: You want to use the [`operator`
module](http://docs.python.org/2/library/operator.html) here, together with a
(short) list of binary numeric operator names, without the underscores for
compactness:

    
    
    import operator 
    
    numeric_ops = 'add div floordiv mod mul pow sub truediv'.split()
    
    def delegated_arithmetic(handler):
        def add_op_method(op, cls):
            op_func = getattr(operator, op)
            def delegated_op(self, k):
                getattr(self, handler)(lambda x: op_func(x, k))
            setattr(cls, '__{}__'.format(op), delegated_op)
    
        def add_reflected_op_method(op, cls):
            op_func = getattr(operator, op)
            def delegated_op(self, k):
                getattr(self, handler)(lambda x: op_func(k, x))
            setattr(cls, '__r{}__'.format(op), delegated_op)
    
        def decorator(cls):
            for op in numeric_ops:
                add_op_method(op, cls)
                add_reflected_op_method(op, cls) # reverted operation
                add_op_method('i' + op, cls)     # in-place operation
            return cls
    
        return decorator
    

Now just decorate your class:

    
    
    @delegated_arithmetic('_update')
    class Foo:
        # ... other methods ...
        def _update(self, f):
            # ... returns a new Foo() object based on transforming
            #     one or more data members with a function f()
    

The decorator takes the name you wanted to delegate the call to to make this a
little more generic.

Demo:

    
    
    >>> @delegated_arithmetic('_update')
    ... class Foo(object):
    ...     def _update(self, f):
    ...         print 'Update called with {}'.format(f)
    ...         print f(10)
    ... 
    >>> foo = Foo()
    >>> foo + 10
    Update called with <function <lambda> at 0x107086410>
    20
    >>> foo - 10
    Update called with <function <lambda> at 0x107086410>
    0
    >>> 10 + foo
    Update called with <function <lambda> at 0x107086410>
    20
    >>> 10 - foo
    Update called with <function <lambda> at 0x107086410>
    0
    

