I have a class that adds two points (one of which is of type Point, and the other is a tuple or list -- see code). My problem is that my add method will only work if I input the numbers in a certain order. I need to create a second method (per the rules in this assignment) that only contains one line calling the add method and returns the result and can supposedly be found in the data model of the documentation.
class Point():
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return ("X = " + str(self.x) + "\nY = " + str(self.y))
def __add__(self, other):
if isinstance(other,list) or isinstance(other,tuple):
newX = other[0] + self.x
newY = other[1] + self.y
return(Point(newX,newY))
else:
newX = self.x + other
newY = self.y + other
return(Point(newX,newY))
p = Point(5,10)
print(p + [3.5,6])
print([3.5,6] + p)
I've scoured the data model and I can only think that reversed or something with getattr would work, but I have no idea how to implement either, or if I'm even on the right track. Please help!
You should add the __radd__()
in your class:
def __radd__(self, *args, **kwargs):
return self.__add__(*args, **kwargs)
This will actually do an __add__()
as in this case it really is the same.
but you may consider making the class behave like a list, something like this:
class Point():
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self._list = [self.x, self.y]
def __str__(self):
return ("X = " + str(self.x) + "\nY = " + str(self.y))
def __repr__(self):
return str(self._list)
def __iter__(self):
for elem in self._list:
yield elem
def __getitem__(self, i):
return self._list(i)
def __len__(self):
return len(self._list)
def __delitem__(self, i):
#not sure if you really want this
del self._list[i]
def __setitem__(self, i, val):
#not sure if you really want this
self._list[i] = val
def __add__(self, other):
#this code could be optimized
#using your original code for this example
if isinstance(other,list) or isinstance(other,tuple):
newX = other[0] + self.x
newY = other[1] + self.y
else:
newX = self.x + other
newY = self.y + other
#returning a list
return [newX, newY]
def __radd__(self, *args, **kwargs):
return self.__add__(*args, **kwargs)
p = Point(5,10)
print(p)
print(p + [3.5,6])
print([3.5,6] + p)
output:
[5, 10]
[8.5, 16]
[8.5, 16]
[edit] If you do decide to make it behave like a list
, you might as well subclass list
, example:
class Point(list):
def __init__(self, x=0, y=0):
super(Point, self).__init__([x, y])
def __add__(self, other):
if isinstance(other, (list, tuple)):
return [sum(i) for i in zip(self, other)]
elif isinstance(other, (int, float)):
return [i + other for i in self]
else:
return self
def __radd__(self, *args, **kwargs):
return self.__add__(*args, **kwargs)
#you probably want a __sub__
def __sub__(self, other):
if isinstance(other, (list, tuple)):
return [i - j for i, j in zip(self, other)]
elif isinstance(other, (int, float)):
return [i - other for i in self]
else:
return self
#and an __rsub__
def __rsub__(self, other):
if isinstance(other, (list, tuple)):
return [i - j for i, j in zip(other, self)]
elif isinstance(other, (int, float)):
return [other - i for i in self]
else:
return self
#take away functions you do not want
def pop(*args, **kwargs): pass
def sort(*args, **kwargs): pass
def append(*args, **kwargs): pass
def extend(*args, **kwargs): pass
def insert(*args, **kwargs): pass
def remove(*args, **kwargs): pass
def reverse(*args, **kwargs): pass
p = Point(5,10)
tests = [[3.5, 6], (5,4), 1.1, 'wrong string', [1, 2, 3]]
for test in tests:
print(p + test)
print(test + p)
for test in tests:
print(p - test)
print(test - p)
p.append(4)
print(p)
output:
[8.5, 16]
[8.5, 16]
[10, 14]
[10, 14]
[6.1, 11.1]
[6.1, 11.1]
[5, 10]
[5, 10]
[6, 12]
[6, 12]
[1.5, 4]
[-1.5, -4]
[0, 6]
[0, -6]
[3.9, 8.9]
[-3.9, -8.9]
[5, 10]
[5, 10]
[4, 8]
[-4, -8]
[5, 10]