3

I have written the following code that works.

from operator import mul
from operator import truediv #python 3.2

class Vec(list):

    def __mul__(self, other):
        return Vec(map(mul, self, other))

    def __truediv__(self, other):
        return Vec(map(truediv, self, other))


>>> xs = Vec([1,2,3,4,5])
>>> ys = Vec([4,5,6,7,4])
>>> zs = xs * ys
>>> zs.__class__
<class 'vector.Vec'>
>>> zs
[4, 10, 18, 28, 20]

but is it possible to create something like this:

class Vec(list):

    allowed_math = [__add__, __mul__, __truediv__, __subtract__] # etc

    def __catchfunction__(self, other, function):
        if function in allowed_math:
            return Vec(map(function, self, other))

Just to make clear, This in not about me trying to re-create NumPy, I am merely trying to understand how one can play with Python.

beoliver
  • 5,579
  • 5
  • 36
  • 72

2 Answers2

3

One option to achieve the desired effect is this:

class Vec(list):
    pass

functions = {"__add__": operator.add,
             "__mul__": operator.mul,
             "__truediv__": operator.truediv,
             "__sub__": operator.sub}
for name, op in functions.iteritems():
    setattr(Vec, name, lambda self, other, op=op: Vec(map(op, self, other)))

Note that the op=op parameter is necessary to avoid the lambda function becoming a closure over op.

You might be much better off using NumPy though – it offers a much more versatile and efficient numerical array implementation than you would be able to create yourself in pure Python.

beoliver
  • 5,579
  • 5
  • 36
  • 72
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • apropos NumPy, completely agree, but this was more a question of me thinking about how one might do it. – beoliver Jun 26 '12 at 13:43
  • 1
    I'm pretty sure that implementing `__getattr__` will not work; `__methods__` circumvent normal attribute lookup for efficiency and can't be trapped in this manner. – Matt Anderson Jun 26 '12 at 13:48
  • So what you would suggest is create a dictionary with all the functions that I want to include, and then use a single fuction to set all of the class' attributes? So a class can really not "see" what functions are being passed to it? or do I mean the class is being passed to? – beoliver Jun 26 '12 at 13:51
  • @MattAnderson: You are right – since we are deriving from `list`, we get a new-style class. – Sven Marnach Jun 26 '12 at 13:58
  • @ThemanontheClaphamomnibus: The code does not use a single funtion for all special methods – it dynamically creates a new function for each of them. Special methods are internally stored in "slots" for each operation. If two objects should be multiplied, Python looks up the multiplication function in the corresponding slot of the type of the first object. Assigning to the `__mul__` attribute of a type implicitly updates this slot. This is also why the `__getattr(ibute)__()` approach does not work. – Sven Marnach Jun 26 '12 at 14:05
0

The important thing to know is that per http://docs.python.org/reference/datamodel.html#new-style-special-lookup ( http://docs.python.org/dev/reference/datamodel.html#special-method-lookup for Python 3):

For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary. ... implicit special method lookup generally also bypasses the __getattribute__() method even of the object’s metaclass.

So the only to implement operator overloading through special method names is by defining them on the class (either inline or after class creation programmatically).

See http://code.activestate.com/recipes/577812-see-how-__getattribute__-interacts-with-special-me/ for some more detail and examples. See also Overriding special methods on an instance for a related question.

Community
  • 1
  • 1
ecatmur
  • 152,476
  • 27
  • 293
  • 366