User defined __mul__ method is not commutative - python

I wrote a class to represent vectors in Python (as an exercise) and I'm having problems with extending the built-in operators.
I defined a __mul__ method for the vector class. The problem is that in the expression x * y the interpreter calls the __mul__ method of x, not y.
So vector(1, 2, 3) * 2 returns a vector <2, 4, 6> just like it should; but 2 * vector(1, 2, 3) creates a TypeError because the built-in int class does not support multiplication by my user-defined vectors.
I could solve this problem by simply writing a new multiplication function
def multiply(a, b):
try:
return a * b
except TypeError:
return b * a
but this would require redefining every function that I want to use with my user-defined classes.
Is there a way to make the built-in function handle this correctly?

If you want commutativity for different types you need to implement __rmul__(). If implemented, it is called, like all __r*__() special methods, if the operation would otherwise raise a TypeError. Beware that the arguments are swapped:
class Foo(object):
def __mul_(self, other):
''' multiply self with other, e.g. Foo() * 7 '''
def __rmul__(self, other):
''' multiply other with self, e.g. 7 * Foo() '''

I believe you are looking for __rmul__

Related

How to subclass "float" without implementing its method?

I want to subclass from float but don't want it to init soon. I also don't want to explicitly call float() for my object.
For example, I don't want to calculate anything before it is required. I want only to do an object that behaves like float. Here is how I want to create class:
class MassiveAverage(float):
def __init__(self, floats: list[float]):
self.floats = floats
def __float__(self) -> float:
return sum(self.floats) / len(self.floats)
And this is how I want to use it:
massive_average = MassiveAverage([1.1, 2.2]) # no any calculations
massive_sum = massive_average * 2 # this is were it calculates its float value
For the answer to this question I am going to assume you are already familiar with python's "magic methods". #gftea's answer has a link to the documentation for some of the magic methods if you are not familiar.
You are going to have to manually define each "magic function" __mul__, __add__, __sub__, etc.
class MassiveAverage:
def __init__(self, floats):
self._avg = sum(floats)/len(floats)
def __mul__(self, other):
return self._avg * other
def __sub__(self, other):
return self._avg - other
def __add__(self, other):
return self._avg + other
...
But, this doesn't handle your lazy evaluation use case. Instead, we could maintain an internal cache, and on the first time one of these magic methods are evaluated, we could run the average function.
class MassiveAverage:
def __init__(self, floats):
self._floats = floats
self._avg = None
#property
def avg(self):
if self._avg is None:
self._avg = sum(self._floats) / len(self._floats)
return self._avg
Then, we can replace our magic functions and use self.avg.
def __mul__(self, other):
return self.avg * other
def __add__(self, other):
return self.avg + other
def __sub__(self, other):
return self.avg - other
...
Unfortunately, you cannot subclass float in the manner you want. Because you are specifying lazy evaluation, you are fundamentally changing how the methods in the float class work (since they don't need lazy evaluation). You would still have to manually change each magic method.
you should overwrite the operator, for example, to overwrite *, you can overwrite the __mul__ method
def __mul__(self, float): ...
see below for methods can be defined to emulate numeric objects
https://docs.python.org/3/reference/datamodel.html?highlight=rmul#emulating-numeric-types
__float__ is used for exactly one purpose: to define the behavior of float(x) as x.__float__(). There is no implicit conversion in an expression like massive_average * 2. This could mean any number of things:
massive_average.__int__() * 2
massive_average.__float__() * 2
massive_average.__complex__() * 2
massive_avarge.__str__() * 2
so Python refuses to guess. It will try massive_average.__mul__(2), and failing that, (2).__rmul__(massive_average), before giving up.
Each of the type-specific "conversion" methods are used only by the corresponding type itself. print, for example, does not call __str__ (directly); it only is defined to call str on each of its arguments, and str takes care of calling __str__.

How to make a Python class instance pretend to be certain type (e.g. float)? [duplicate]

So, I've got a custom class that has a __mul__ function which works with ints. However, in my program (in libraries), it's getting called the other way around, i.e., 2 * x where x is of my class. Is there a way I can have it use my __mul__ function for this?
Just add the following to the class definition and you should be good to go:
__rmul__ = __mul__
Implement __rmul__ as well.
class Foo(object):
def __mul__(self, other):
print '__mul__'
return other
def __rmul__(self, other):
print '__rmul__'
return other
x = Foo()
2 * x # __rmul__
x * 2 # __mul__

What does this lambda function do?

I'm still struggling with lambdas. This code was submitted as an answer to Python: closest coordinate?. A lot of it confused me, but I've sorted through most of it. The float method's use of self is still a little tricky for me (I get self.x and self.y, but not really sure what self is in that context). Only mentioning that as it is likely involved in the main part I don't understand, which is the lambda function in the closest method. I see it's going to return the minimum item generated, and that it unpacks the points as args. Then I get a little lost. Are __sub__ and __pow__ redefining - and ** respectively, or are they just distinct methods?
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def closest(self,*points):
return min(points,key=lambda x:float(x-self))
def __sub__(self,other):
return Point((self.x-other.x) , (self.y - other.y))
def __pow__(self,powTo):
return Point(self.x**powTo,self.y**powTo)
def __iter__(self):
yield self.x
yield self.y
def __float__(self):
return sum(self**2)**0.5
def __str__(self):
return "(%s,%s)"%(self.x,self.y)
pt0 = Point(9,2)
print pt0.closest(Point(0,0),Point(10,0),Point(10,10))
lambda args: expr is not a special magic feature, it's just nice shorthand for
def someFunc(args):
return expr
which is mainly useful when you need a small function with a simple expression for its body and you don't care about the name. If we used familiar syntax, the closest() method would be:
def closest(self,*points):
def keyFunc(x):
return float(x-self)
return min(points,key=keyFunc)
that is, it creates a small, one off function which does a little bit of calculation depending on self and its argument x, and passes that into the min() builtin function. As Ostrea explains, min(seq, key=f) returns the item x in seq which minimizes f(x)
def __sub__ is one of the magic methods you can define on an object.
It will be called when you substract the two points. In the example, self will be pt0.
Yes, __sub__ and __pow__ redefines - and ** respectively. In this example you just pass anonymous function to optional argument for min(). Here is what this optional argument does, as said in docs:
The optional keyword-only key argument specifies a one-argument ordering function like that used for list.sort().
In this anonymous function you just subtract point, on which closest was called from points, which was passed as arguments and then convert it to float (this conversion is overridden, see __float__)

Using Python tuples as vectors

I need to represent immutable vectors in Python ("vectors" as in linear algebra, not as in programming). The tuple seems like an obvious choice.
The trouble is when I need to implement things like addition and scalar multiplication. If a and b are vectors, and c is a number, the best I can think of is this:
tuple(map(lambda x,y: x + y, a, b)) # add vectors 'a' and 'b'
tuple(map(lambda x: x * c, a)) # multiply vector 'a' by scalar 'c'
which seems inelegant; there should be a clearer, simpler way to get this done -- not to mention avoiding the call to tuple, since map returns a list.
Is there a better option?
NumPy supports various algebraic operations with its arrays.
Immutable types are pretty rare in Python and third-party extensions thereof; the OP rightly claims "there are enough uses for linear algebra that it doesn't seem likely I have to roll my own" -- but all the existing types I know that do linear algebra are mutable! So, as the OP is adamant on immutability, there is nothing for it but the roll-your-own route.
Not that there's all that much rolling involved, e.g. if you specifically need 2-d vectors:
import math
class ImmutableVector(object):
__slots__ = ('_d',)
def __init__(self, x, y):
object.__setattr__(self, _d, (x, y))
def __setattr__(self, n, v):
raise ValueError("Can't alter instance of %s" % type(self))
#property
def x(self):
return self._d[0]
#property
def y(self):
return self._d[1]
def __eq__(self, other):
return self._d == other._d
def __ne__(self, other):
return self._d != other._d
def __hash__(self):
return hash(self._d)
def __add__(self, other):
return type(self)(self.x+other.x, self.y+other.y)
def __mul__(self, scalar):
return type(self)(self.x*scalar, self.y*scalar)
def __repr__(self):
return '%s(%s, %s)' % (type(self).__name__, self.x, self.y)
def __abs__(self):
return math.hypot(self.x, self.y)
I "threw in for free" a few extras such as .x and .y R/O properties, nice string representation, usability in sets or as keys in dicts (why else would one want immutability?-), low memory footprint, abs(v) to give v's vector-length -- I'm sure you can think of other "wouldn't-it-be-cool-if" methods and operators, depending on your application field, and they'll be just as easy. If you need other dimensionalities it won't be much harder, though a tad less readable since the .x, .y notation doesn't apply any more;-) (but I'd use genexps, not map).
By inheriting from tuple, you can make a nice Vector class pretty easily. Here's enough code to provide addition of vectors, and multiplication of a vector by a scalar. It gives you arbitrary length vectors, and can work with complex numbers, ints, or floats.
class Vector(tuple):
def __add__(self, a):
# TODO: check lengths are compatable.
return Vector(x + y for x, y in zip(self, a))
def __mul__(self, c):
return Vector(x * c for x in self)
def __rmul__(self, c):
return Vector(c * x for x in self)
a = Vector((1, 2, 3))
b = Vector((2, 3, 4))
print a + b
print 3 * a
print a * 3
Although using a library like NumPy seems to be the resolution for the OP, I think there is still some value in a simple solution which does not require additional libraries and which you can stay immutable, with iterables.
Using the itertools and operators modules:
imap(add, a, b) # returns iterable to sum of a and b vectors
This implementation is simple. It does not use lambda neither any list-tuple conversion as it is iterator based.
from itertools import imap
from operator import add
vec1 = (1, 2, 3)
vec2 = (10, 20, 30)
result = imap(add, vec1, vec2)
print(tuple(result))
Yields:
(11, 22, 33)
Why not create your own class, making use of 2 Cartesian point member variables? (sorry if the syntax is a little off, my python is rusty)
class point:
def __init__(self,x,y):
self.x=x
self.y=y
#etc
def add(self,p):
return point(self.x + p.x, self.y + p.y)
class vector:
def __init__(self,a,b):
self.pointA=a
self.pointB=b
#etc
def add(self,v):
return vector(self.pointA + v.pointA, self.pointB + v.pointB)
For occasional use, a Python 3 solution without repeating lambdas is possible via using the standard operator package:
from operator import add, mul
a = (1, 2, 3)
b = (4, 5, 6)
print(tuple(map(add, a , b)))
print(tuple(map(mul, a , b)))
which prints:
(5, 7, 9)
(4, 10, 18)
For serious linear algebra computations using numpy vectors is the canonical solution:
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a+b)
print(a*b)
which prints:
[5 7 9]
[ 4 10 18]
Since pretty much all of the sequence manipulation functions return lists, that's pretty much what you're going to have to do.

Possible to use more than one argument on __getitem__?

I am trying to use
__getitem__(self, x, y):
on my Matrix class, but it seems to me it doesn't work (I still don't know very well to use python).
I'm calling it like this:
print matrix[0,0]
Is it possible at all to use more than one argument? Thanks. Maybe I can use only one argument but pass it as a tuple?
__getitem__ only accepts one argument (other than self), so you get passed a tuple.
You can do this:
class matrix:
def __getitem__(self, pos):
x,y = pos
return "fetching %s, %s" % (x, y)
m = matrix()
print m[1,2]
outputs
fetching 1, 2
See the documentation for object.__getitem__ for more information.
Indeed, when you execute bla[x,y], you're calling type(bla).__getitem__(bla, (x, y)) -- Python automatically forms the tuple for you and passes it on to __getitem__ as the second argument (the first one being its self). There's no good way[1] to express that __getitem__ wants more arguments, but also no need to.
[1] In Python 2.* you can actually give __getitem__ an auto-unpacking signature which will raise ValueError or TypeError when you're indexing with too many or too few indices...:
>>> class X(object):
... def __getitem__(self, (x, y)): return x, y
...
>>> x = X()
>>> x[23, 45]
(23, 45)
Whether that's "a good way" is moot... it's been deprecated in Python 3 so you can infer that Guido didn't consider it good upon long reflection;-). Doing your own unpacking (of a single argument in the signature) is no big deal and lets you provide clearer errors (and uniform ones, rather than ones of different types for the very similar error of indexing such an instance with 1 vs, say, 3 indices;-).
No, __getitem__ just takes one argument (in addition to self). In the case of matrix[0, 0], the argument is the tuple (0, 0).
You can directly call __getitem__ instead of using brackets.
Example:
class Foo():
def __init__(self):
self.a = [5, 7, 9]
def __getitem__(self, i, plus_one=False):
if plus_one:
i += 1
return self.a[I]
foo = Foo()
foo[0] # 5
foo.__getitem__(0) # 5
foo.__getitem__(0, True) # 7
I learned today that you can pass double index to your object that implements getitem, as the following snippet illustrates:
class MyClass:
def __init__(self):
self.data = [[1]]
def __getitem__(self, index):
return self.data[index]
c = MyClass()
print(c[0][0])

Categories