python refactoring (similar methods in class) - python

Python refactoring
Both the add and sub are very similar. How does one re-factor code like this? The logic is basically inverse of each other.
class point(object):
def __init__( self, x, y ):
self.x, self.y = x, y
def add( self, p ):
x = self.x + p.x
y = self.y + p.y
return point( x, y )
def sub( self, p ):
x = self.x - p.x
y = self.y - p.y
return point( x, y )

First, standard practice is to capitalize classes (so Point, not point). I'd make use of the __add__ and __sub__ (and possibly __iadd__ and __isub__) methods, as well. A first cut might look like this:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, p):
return Point(self.x + p.x, self.y + p.y)
def __sub__(self, p):
return Point(self.x - p.x, self.y - p.y)
I know you're looking to pull the logic out into a single method, something like:
class Point(object):
def __init__(self, x, y):
self.x = x
self.y = y
def _adjust(self, x, y):
return Point(self.x + x, self.y + y)
def __add__(self, p):
return self._adjust(p.x, p.y)
def __sub__(self, p):
return self._adjust(-p.x, -p.y)
... but that seems more complicated, without much gain.

What about that:
import operator
class point(object):
def __init__( self, x, y ):
self.x, self.y = x, y
def _do_op(self, op, p):
x = op(self.x, p.x)
y = op(self.y, p.y)
return point(x, y)
def add( self, p ):
return self._do_op(operator.add, p)
def sub( self, p ):
return self._do_op(operator.sub, p)

Here's something you could do.
def __add__(self, p): # used this so that you can add using the + operator
x = self.x + p.x
y = self.y + p.y
return point(x, y)
def __sub__(self, p):
return self + point(-p.x, -p.y)

Related

TypeError: Vector() takes no arguments

I am trying to Implement the set_x, set_y, init, and str methods in the class Vector above, the output of this test should be:
#Vector: x=4, y=4
#Vector: x=5, y=5
#Vector: x=3, y=7
#Vector: x=3, y=7
.
class Vector:
def __init__(self, x, y): self.x = x self.y = y
def set_x(self,x): set_x = x
def set_y(self,y): set_y = y
def __str__(self): return ("Vector: x=%s, y=%s", set_x, set_y)
#__init__ and __str__ v1=Vector(4,4) print(v1)
#Important Remark
#v1.x,v1.y =4,4 # should return an error since x and y are private
# test set_x and set_y v1.set_x(5) v1.set_y(5) print(v1)
v1.set_x(1) v1.set_y(9) print(v1)
# test __init__ again print(Vector(1,9))
I believe this is what you are trying to do:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def set_x(self, x):
self.x = x
def set_y(self, y):
self.y = y
def __str__(self):
return f"Vector: x={self.x}, y={self.y}"
v1 = Vector(1, 9)
print(v1)

Where does the value of the variable in the subclass go?

class A(object):
def __init__(self, x):
self.x = x
def f(self, x):
return 2*x
def g(self, x):
return self.f(x)
class B(A):
def g(self, y):
return 3*y + self.x
class C1(B):
def __init__(self, x, y):
B.__init__(self,x)
self.y = y
def f(self, x):
return self.x + self.y
class C2(B):
def __init__(self, x, y):
B.__init__(self,x)
self.y = y
def f(self, x):
return x + self.x + self.y
a = A(5)
b = B(2)
c1 = C1(3,5)
c2 = C2(3,5)
When I do "What does the expression c2.f(4) evaluate to?", I was not sure where self.x in the f function in class C2 points to.
Could you give me some suggestions?
c2.f(4) makes 12. The value of x in function f is 4 because that is the argument in c2.f(4). The value of c2's self.x is 3 because C2 inherits from B, which inherits from A, where the line self.x = x occurs. In this line, x is what is entered in the line c2 = C2(3,5) and because it is assigned to self.x, c2's self.x is 3. Because of the line self.y = y in class C2, the instance c2's y value is what is entered in the line c2 = C2(3,5), 5. 4 + 3 + 5 makes 12.

Python giving me two different results while performing the same operation on the same objects twice

I created a class vector2D in python with a method to add vectors. Then I used it to add the same vectors twice and got different results. Why did that happen?
Here's the code:
class vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
self.x += other.x
self.y += other.y
return self.x, self.y
#Creating vector objects
v1 = vector2D(2, 3)
v2 = vector2D(4, 8)
#using the redefined addition operator to add vector objects
v = v1 + v2 #output: (6, 11)
print(v)
#Adding again
v = v1 + v2 #output: (10, 19)
print(v)
You both add the vectors in place and return the result!
def __add__(self, other):
self.x += other.x
self.y += other.y
return self.x, self.y
This changes first vector's parameters! += means self.x = self.x + other.x.
Do this instead:
def __add__(self, other):
result_x = self.x + other.x
result_y = self.y + other.y
return result_x, result_y
Your doing in place assignment, when you do this
self.x += other.x
you are changing the x attribute of the object it self, so when you do the second addition the x is changed.
One more thing __add__ should return an instance of the same class, Developer when using your class they will expect when they add vector2d to another vector2d they get a vector2d but you are returning a tuple:
class vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return self.__class__(self.x + other.x, self.y + other.y)
So when you add vector2D + vector2D you get vector2D instance.

Addition doesn't work due to AttributeError: 'Circle' object has no attribute 'x'

I have the following code which has 2 classes- A point and a circle:
import math
class Point:
"""Two-Dimensional Point(x, y)"""
def __init__(self, x=0, y=0):
# Initialize the Point instance
self.x = x
self.y = y
def __iter__(self):
yield self.x
yield self.y
def __iadd__(self, other):
self.x = self.x + other.x
self.y = self.y + other.y
return self
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __mul__(self, other):
mulx = self.x * other
muly = self.y * other
return Point(mulx, muly)
def __rmul__(self, other):
mulx = self.x * other
muly = self.y * other
return Point(mulx, muly)
#classmethod
def from_tuple(cls, tup):
x, y = tup
return cls(x, y)
def loc_from_tuple(self, tup):
# self.x=t[0]
# self.y=t[1]
self.x, self.y = tup
#property
def magnitude(self):
# """Return the magnitude of vector from (0,0) to self."""
return math.sqrt(self.x ** 2 + self.y ** 2)
def distance(self, self2):
return math.sqrt((self2.x - self.x) ** 2 + (self2.y - self.y) ** 2)
def __str__(self):
return 'Point at ({}, {})'.format(self.x, self.y)
def __repr__(self):
return "Point(x={},y={})".format(self.x, self.y)
class Circle(Point):
"""Circle(center, radius) where center is a Point instance"""
def __init__(self, center= Point(0,0), radius=1):
# Point.__init__(self,center)
self.center = 1 * center
self.radius = radius
# if not isinstance(center,Point):
# raise TypeError("The center must be a Point!")
#property
def center(self):
return self._center
#center.setter
def center(self, _center):
self._center = _center
if (isinstance(self._center, Point) is False):
raise TypeError("The center must be a Point!")
def __getitem__(self,item):
return self.center[item]
def __add__(self,other):
return Circle(
Point(self.center.x + other.center.x, self.center.y+other.center.y),
self.radius + other.radius)
#classmethod
def from_tuple(cls, center,radius):
return cls(center, radius)
#property
def radius(self):
return self._radius
#radius.setter
def radius(self, radius):
if radius < 0:
raise ValueError('The radius cannot be negative')
self._radius = radius
#property
def area(self):
"""Calculate and return the area of the Circle"""
return math.pi * self.radius ** 2
#property
def diameter(self):
"""Calculate and return the diameter of the Circle"""
return self.radius * 2
def __str__(self):
return "Circle with center at ({0}, {1}) and radius {2}".format(self.center.x, self.center.y, self.radius)
def __repr__(self):
return "Circle(center=Point({0}, {1}), radius={2})".format(self.center[0],self.center[1],self.radius)
The normal addition works as expected but the += does not. The following is the expected output.
circle1 = Circle(radius=2.5, center=Point(1, 1))
circle2 = Circle(center=Point(2, 3), radius=1)
id1 = id(circle1)
circle1 += circle2
print(circle2)
Circle(center=Point(2, 3), radius=1)
print(circle1)
Circle(center=Point(3,4), radius=3.5)
print(id1 == id(circle1))
True
When I try to run this, I get the following error:
Traceback (most recent call last):
File "/Users/ayushgaur/Downloads/HW8_files (1)/shapes.py", line 206, in
circle1 += circle2
File "/Users/ayushgaur/Downloads/HW8_files (1)/shapes.py", line 18, in iadd
self.x = self.x + other.x
AttributeError: 'Circle' object has no attribute 'x
Can anyone see why this is happening?
class Circle(Point): means that the class Circle is inherited from the class Point and therefore the function __iadd__ of Point too. I do not see why you would want to inherit Circle from Point.
I would suggest removing the inheritance, i.e. having simply class Circle: and defining a function __iadd__ for circle which is the function that defines what circle1 += circle2 does.
Circle inherited Point's __iadd__() method, used when += is called.
You may want to override the __iadd__() method by:
def __iadd__(self, other):
return self.add(self, other)

Add two sets of coordinates in Python using a class?

I'm trying to add two sets of coordinates using a class in python. This is what I have so far.
class Position:
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, x):
self.x = self + x
And in a different program to run the class I have
A = Position(1, 1)
B = Position(2, 3)
A.add(B)
A.print()
So I am trying to add A and B to get (3,4). How would I do that using the add class? I don't know what to set for the parameters or what to put in the body of the function to make it work. Thanks
Convert add to be
def add(self, other):
self.x = self.x + other.x
self.y = self.y + other.y
That said, it's often useful to work with immutable objects, so why not have add return a new Position
def add(self, other):
return Position(self.x + other.x, self.y + other.y)
Then if you really want to get funky, why not override __add__()
def __add__(self, other):
return Position(self.x + other.x, self.y + other.y)
This will let you add two points together using the '+' operator.
a = Position(1, 1)
b = Position(2, 3)
c = a + b
You want something like this:
class Position(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
"Add two Positions and return a new one."
return Position(self.x + other.x, self.y + other.y)
__radd__ = __add__
def __iadd__(self, other):
"In-place add += updates the current instance."
self.x += other.x
self.y += other.y
return self
def __str__(self):
"Define the textual representation of a Position"
return "Position(x=%d, y=%d)" % (self.x, self.y)
__repr__ = __str__
Now your Position class can be added using the regular Python + operator and printed using the regular print statement:
A = Position(1, 2)
B = Position(2, 3)
A += B
print(A)
Well, I'm not completely sure you actually want to change your point. If you want to change your point, I would do
class Position:
def __init__(self,x,y):
self.x = x
self.y = y
def add(self,other):
self.x += other.x
self.y += other.y
Alternatively, and more commonly (for Positions, I'd say, you'd want to get a new position)
class Position:
def __init__(self,x,y):
self.x = x
self.y = y
def __add__(self,other):
return Position(self.x + other.x, self.y + other.y)
This way, if you overrode __eq__
Position(1,2) + Position(3,4) == Position(4,6)
you may want to just import numpy and use numpy.array instead of rolling your own Position class.

Categories

Resources