Generic binary operation in a class definition?
<p>I am writing a tiny linear algebra module in Python 3, and there are a number of binary operators to define. Since each definition of a binary operator is essentially the same with only the operator itself changed, I would like to save some work by writing a generic binary operator definition only once.</p>

<p>For example:</p>

<pre><code>class Vector(tuple):
    def __new__(self, x):
        super().__new__(x)

    # Binary operators

    def __add__(self, xs):
        try:
            return Vector(a + x for a, x in zip(self, xs)))
        except:
            return Vector(a + x for a in self)

    def __and__(self, xs):
        try:
            return Vector(a &amp; x for a, x in zip(self, xs))
        except:
            return Vector(a &amp; x for a in self)

    ... # mul, div, or, sub, and all other binary operations
</code></pre>

<p>The binary operators above all have the same form. Only the operator is changed. I wonder if I could instead write all operators at once, something like this:</p>

<pre><code>def __bop__(self, xs):
    bop = get_bop_somehow()
    try:
        return Vector(bop(a, x) for a, x in zip(self, xs)))
    except:
        return Vector(bop(a, x) for a in self)
</code></pre>

<p>I've heard that Python can do magical things with the <code>__getattr__</code> method, which I tried to use to extract the name of the operator like so:</p>

<pre><code>def __getattr__(self, name):
    print('Method name:', name.strip('_'))
</code></pre>

<p>But, unfortunately, this only works when called using the full method name, not when an operator is used. How can I write a one-size-fits-all binary operator definition?</p>

<h2>Update:</h2>

<p>This might be super-slow, but you can create an abstract class with all of the binary methods and inherit from it.</p>

<pre><code>import operator

def binary_methods(cls):
    operator_list = (
        '__add__', '__sub__', '__mul__', '__truediv__', 
        '__floordiv__', '__and__', '__or__', '__xor__'
    )

    for name in operator_list:
        bop = getattr(operator, name)
        method = cls.__create_binary_method__(bop)
        setattr(cls, name, method)

    return cls

@binary_methods
class AbstractBinary:
    @classmethod
    def __create_binary_method__(cls, bop):
        def binary_method(self, xs):
            try:
                return self.__class__(bop(a, x) for a, x in zip(self, xs))
            except:
                return self.__class__(bop(a, x) for a in self)
        return binary_method

class Vector(AbstractBinary, tuple):
    def __new__(self, x):
        return super(self, Vector).__new__(Vector, x)
</code></pre>

<hr>

<h2>Original:</h2>

<p>Okay, I think I've got a working solution (only tested in Python 2.X) that uses a class decorator to dynamically create the binary methods.</p>

<pre><code>import operator

def add_methods(cls):
    operator_list = ('__add__', '__and__', '__mul__')

    for name in operator_list:
        func = getattr(operator, name)
        # func needs to be a default argument to avoid the late-binding closure issue
        method = lambda self, xs, func=func: cls.__bop__(self, func, xs)
        setattr(cls, name, method)

    return cls

@add_methods
class Vector(tuple):
    def __new__(self, x):
        return super(self, Vector).__new__(Vector, x)

    def __bop__(self, bop, xs):
        try:
            return Vector(bop(a, x) for a, x in zip(self, xs))
        except:
            return Vector(bop(a, x) for a in self)
</code></pre>

<p>Here's some example usage:</p>

<pre><code>v1 = Vector((1,2,3))
v2 = Vector((3,4,5))

print v1 * v2 
# (3, 8, 15)
</code></pre>

python class