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>

<p>You <em>can</em> do magical things with <code>__getattr__</code>, but if you can avoid doing so then I would - it starts to get complicated! In this situation you'd likely need to overwrite <code>__getattribute__</code>, but please don't because you will bite yourself in the seat of your own pants if you start messing around with <code>__getattribute__</code>.</p>

<p>You can achieve this in a very simple way, by simply defining the first one, and then doing <code>__and__ = __add__</code> in the other functions.</p>

<pre><code>class MyClass(object):
    def comparison_1(self, thing):
        return self is not thing

    comparison_2 = comparison_1


A = MyClass()

print A.comparison_1(None)
print A.comparison_2(None)
print A.comparison_1(A)
print A.comparison_2(A)
</code></pre>

<p>gives</p>

<pre><code>$ python tmp_x.py 
True
True
False
False
</code></pre>

<p>However, I'm not a fan of this kind of hackery. I would just do</p>

<pre><code>class MyClass(object):
    def comparison_1(self, thing):
        "Compares this thing and another thing"
        return self is not thing

    def comparison_2(self, thing):
        "compares this thing and another thing as well"
        return self.comparison_1(thing)
</code></pre>

<p>Better to write the extra couple of lines for clarity.</p>

<h1>EDIT:</h1>

<p>So I tried it with <code>__getattribute__</code>, doesn't work :/. I admit I don't know why.</p>

<pre><code>class MyClass(object):
    def add(self, other):
        print self, other
        return None

    def __getattribute__(self, attr):
        if attr == '__add__':
            attr = 'add'

        return object.__getattribute__(self, attr)


X = MyClass()
print X.__add__
X + X
</code></pre>

<p>Doesn't work :/</p>

<pre><code>andy@batman[18:15:12]:~$ p tmp_x.py 
&lt;bound method MyClass.add of &lt;__main__.MyClass object at 0x7f52932ea450&gt;&gt;
Traceback (most recent call last):
  File "tmp_x.py", line 15, in &lt;module&gt;
    X + X
TypeError: unsupported operand type(s) for +: 'MyClass' and 'MyClass'
</code></pre>

python class