The problem is to implement scalar and inner product in the vector class in Python. Here is the code:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Point(%s, %s)' % (self.x, self.y)
def __mul__(self,other):
x, y = self.x*other.x, self.y*other.y
return self.__class__(x,y)
def __rmul__(self,other):
x,y = other*self.x,other*self.y
return self.__class__(x,y)
def __add__(self,other):
x,y = self.x + other.x, self.y + other.y
return self.__class__(x, y)
def __sub__(self,other):
x,y = self.x - other.x, self.y - other.y
return self.__class__(x, y)
With inner product it works great, but with scalar multiplication(like if I call Point(3,2)*2) it gives the following error:
AttributeError: 'int' object has no attribute 'x'.
How do I fix this?
Look carefully at your __mul__ method:
def __mul__(self,other):
x, y = self.x*other.x, self.y*other.y
return self.__class__(x,y)
When you're trying to multiply a Point and an int, you're passing the int as the second argument (to the other parameter) to Point.__mul__. Then your method will try to access other.x and other.y, and an int doesn't have these attributes:
You can manually check for the type of other and decide whether you should be doing scalar or vector product:
def __mul__(self,other):
if isinstance(other, Point):
x, y = self.x*other.x, self.y*other.y
return self.__class__(x,y)
elif isinstance(other, (int, float, complex)):
x, y = other * self.x, other * self.y
return self.__class__(x, y)
else:
raise TypeError
def __rmul__(self, other):
return self * other
Also, the way you're doing multiplication is strange. A dot product of two vectors should be a number, not a vector.
https://en.wikipedia.org/wiki/Dot_product
You need to add a check for the type of other, it can be a Point instance or other
Here the code for __mul__
def __mul__(self, other):
if isinstance(other, Point):
return Point(self.x * other.x, self.y * other.y) # Point * Point
return Point(self.x * other, self.y * other) # Point * othertype
def __rmul__(self, other):
return Point(self.x * other, self.y * other) # othertype * Point
Related
I am trying to perform the following task :
For two points (𝑥1,𝑦1)+(𝑥2,𝑦2)=(𝑥1+𝑥2,𝑦1+𝑦2)
I have this code executed :
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return "Point({0}, {1})".format(self.x, self.y)
def __add__(self, other):
return [self.x + other.x, self.y + other.y]
def __sub__(self, other):
return [self.x - other.x, self.y - other.y]
when I try to run the following piece of code, it says:
from functools import reduce
def add_sub_results(points):
points = [Point(*point) for point in points]
return [str(reduce(lambda x, y: x + y, points)),
str(reduce(lambda x, y: x - y, points))]
it returns
return [str(reduce(lambda x, y: x + y, points)),
5 str(reduce(lambda x, y: x - y, points))]
6
TypeError: can only concatenate list (not "Point") to list
how can I solve this?
I think your __add__() and __sub__() methods of your Point class should be:
class Point(object):
...
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y) #<-- MODIFIED THIS
def __sub__(self, other):
return Point(self.x - other.x, self.y - other.y) #<-- MODIFIED THIS
This question already has answers here:
User defined __mul__ method is not commutative
(2 answers)
Closed 2 years ago.
I have successfully implemented the inner product like this (its an excercise - some things might beeing imported):
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Point({}, {})'.format(self.x, self.y)
def __add__(self, point):
return Point(self.x + point.x, self.y + point.y)
def __sub__(self, point):
return Point(self.x - point.x, self.y - point.y)
def __mul__(self, second):
if isinstance(second, Point):
return (self.x * second.x + self.y * second.y)
elif isinstance(second, int):
return Point(self.x * second, self.y * second)
elif isinstance(second, float):
return Point(self.x * second, self.y * second)
def __mul__(first, self):
if isinstance(first, int) and isinstance(self, Point):
return Point(self.x * first, self.y * first)
elif isinstance(first, float) and isinstance(self, Point):
return Point(self.x * first, self.y * first)
I get an error if I execute say
p=Point(3.7,4.8)
print(p*3)
Without the last block (scalar mult. from the left) the outout is correct.
Surely there is an error in the last block cause
p=Point(3.7,4.8)
print(3*p)
(which the last block is for) also is not working.
Hope someone can help - thanks!
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Point({}, {})'.format(self.x, self.y)
def __add__(self, point):
return Point(self.x + point.x, self.y + point.y)
def __sub__(self, point):
return Point(self.x - point.x, self.y - point.y)
def __mul__(self, second):
if isinstance(second, Point):
return (self.x * second.x + self.y * second.y)
elif isinstance(second, int) or isinstance(second, float):
return Point(self.x * second, self.y * second)
def __rmul__(first, self):
# no need to confirm that self is an instance of Point
# since we're inside a method of class Point anyway
if isinstance(first, int) or isinstance(first, float):
return Point(self.x * first, self.y * first)
p=Point(3.7,4.8)
print(p*3)
print(p*3.5)
print(3*p)
print(3.5*p)
leads to output
Point(11.100000000000001, 14.399999999999999)
Point(12.950000000000001, 16.8)
None
None
I see, you have mixed up the arguments in the definition of __rmul__. self should always be the first argument (because it is implicitly passed as the first argument), so instead of
def __rmul__(first, self):
write
def __rmul__(self, first):
When you get an error or unexpected output with certain commands, please make sure to include that error/output so other people can better understand what's going on.
In your code, you've defined __mul__ twice; thus the second definition overwrites the first one. I think what you may have meant was to define __mul__ and also __rmul__. Additionally, you're introducing some unnecessary conditions in your if statements. Here's a suggestion:
def __mul__(self, second):
if isinstance(second, Point):
return (self.x * second.x + self.y * second.y)
elif isinstance(second, int) or isinstance(second, float):
return Point(self.x * second, self.y * second)
def __rmul__(self, first):
# no need to confirm that self is an instance of Point
# since we're inside a method of class Point anyway
if isinstance(first, int) or isinstance(first, float):
return Point(self.x * first, self.y * first)
That should solve it, let me know if it doesn't.
class Point(object):
''' A point on a grid at location x, y '''
def __init__(self, x, y):
self.X=x
self.Y=y
def __str__(self):
return "X=" + str(self.X), "Y=" + str(self.Y)
def __add__(self, other):
if not isinstance(other, Point):
raise TypeError("must be of type point")
x= self.X+ other.X
y= self.Y+ other.Y
return Point(x, y)
p1= Point(5, 8)
print p1 + [10, 12]
When trying to add list or tuple at RHS i.e. print p1 + [10, 12], I'm getting
attributeError: int object has no attribute
How can this problem be solved?
First of all I can't reproduce the exact error you show, but I believe that is some sort of a "typo". You are trying to add a list instance to a Point instance, while the __add__ method of the later throws the error whenever you try to add anything that is not a Point instance.
def __add__(self, other):
if not isinstance(other, Point):
raise TypeError("must be of type point")
You could possibly overcome it by adding a fair bit of polymorphism.
from collections import Sequence
class Point(object):
...
def _add(self, other):
x = self.X + other.X
y = self.Y + other.Y
return Point(x, y)
def __add__(self, other):
if isinstance(other, type(self)):
return self._add(other)
elif isinstance(other, Sequence) and len(other) == 2:
return self._add(type(self)(*other))
raise TypeError("must be of type point or a Sequence of length 2")
You may have a comma instead of a plus. Look at
def __str__(self):
return "X=" + str(self.X), "Y=" + str(self.Y)
Which should be
def __str__(self):
return "X=" + str(self.X) + ", Y=" + str(self.Y)
At least on python3 when I correct it your code runs nicely. Obviously using print(p1 + Point(10,12)).
I have a simple vector class that overloards several arithmetic operators:
class vec2:
x = 0.0
y = 0.0
def __add__(self,other):
self.x = other.x
self.y = other.y
def __mul__(self,scalar):
self.x *= scalar
self.y *= scalar
However, somewhere else I call the method like this:
class foo:
position = vec2()
velocity = vec2()
def update(self,dt):
self.position += self.velocity * dt;
However, once I get to the update function, the interpreter gives an error:
'tuple' object has no attribute 'x'
inside the __add__ function.
Why is "other" in __add__ passed as a tuple, and not a vec2?
The entire code is here.
Return new vectors when using __add__ and __mul__, and handle 'strange' types:
class vec2:
x = 0.0
y = 0.0
def __init__(self, x=0.0, y=0.0):
self.x, self.y = x, y
def __add__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
result = self.__class__(self.x, self.y)
result.x += other.x
result.y += other.y
return result
def __iadd__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
self.x += other.x
self.y += other.y
return self
def __mul__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
result = self.__class__(self.x, self.y)
result.x *= other.x
result.y *= other.y
return result
def __imul__(self, other):
if not isinstance(other, self.__class__):
return NotImplemented
self.x *= other.x
self.y *= other.y
return self
To modify the vectors in-place, use __iadd__ and __imul__; these still need to return the new value; this can be self.
Note that this does not handle just passing in a tuple of (x, y) coordinates. If you want to support that usecase, you need to specially handle it:
class foo:
def __init__(self, position=(0.0, 0.0), velocity=(1.0, 1.0)):
self.position = vec2()
self.velocity = vec2(*velocity)
def update(self, dt):
if isinstance(dt, tuple):
dt = vec2(*dt)
self.position += self.velocity * dt;
Note also that you should not really use class attributes for your position and velocity values; I've used instance attributes instead above, and took the opportunity to set both position and velocity to sane values.
Demo:
>>> f = foo()
>>> f.position.x, f.position.y
(0.0, 0.0)
>>> f.update((1, 2))
>>> f.position.x, f.position.y
(1.0, 2.0)
I'm trying to create a class that will allow me to add/multiply/divide objects of the same class together or add/multiply numeric arguments to each member of the class
So my class is for coordinates (I am aware there are great packages out there that do everything I want better than I could ever hope to on my own, but now I'm just curious).
class GpsPoint(object):
"""A class for representing gps coordinates"""
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
return GpsPoint(self.x + other.x, self.y + other.y, self.z + other.z)
def __radd__(self, other):
return GpsPoint(self.x + other, self.y + other, self.z + other)
def __str__(self):
return "%d, %d, %d" % (self.x, self.y, self.z)
This was my original attempt. I found it worked, but only if I used a numeric argument first
>>foo = GpsPoint(1,2,3)
>>print 5 + foo
6, 7, 8
>>print foo + 5
AttributeError: 'int' object has no attribute 'x'
So, what is the pythonic way to do this, is there a pythonic way, is this just silly? I see what the philosophical problem is with using isinstance() and I know I could toss in a try except block I'm just curious how I should go about this.
The "Pythonic" way is to "ask forgiveness rather than permission" - that is, instead of checking the type beforehand, try to add and, if it fails, catch the exception and deal with it, like so:
class GpsPoint(object):
"""A class for representing gps coordinates"""
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
try:
return GpsPoint(self.x + other.x, self.y + other.y, self.z + other.z)
except AttributeError:
return GpsPoint(self.x + other, self.y + other, self.z + other)
def __radd__(self, other):
try:
return GpsPoint(self.x + other.x, self.y + other.y, self.z + other.z)
except AttributeError:
return GpsPoint(self.x + other, self.y + other, self.z + other)
def __str__(self):
return "%d, %d, %d" % (self.x, self.y, self.z)
You are going to have to try to determine what type other is, at least to the extent that it's compatible with GpsPoint. If you can't figure it out then just return NotImplemented and the interpreter will try to handle it from there.
Short answer: use isinstance().
There is no other way to dermine the type of "other" in your methods. Also, if you check the sources of many python libraries you will find that there are lots of places where isinstance() is used. So this is just the state of art in python:-).