Reputation: 11
So, I've written a class to represent vectors called Vector, and i'm trying to write a subclass called Visual_vector that contains additional attributes pertaining to how the vector will be displayed on screen, such as the origin and endpoint of the line to be drawn. My issue is that when I create an instance of Visual_vector, it loses self.origin and self.end_point:
>>> a = Visual_vector((0, 0), (45, 330))
>>> a.x
45
>>> a.y
330
>>> a.length
333.0540496676178
>>> a.origin
>>> a.end_point
I suspect this might have something to do with my use of getattr and setattr in the super class, but other than that I have no idea what the issue is
Vector class:
class Vector():
"""A class to represent a 2D vector"""
def __init__(self, tup):
self.x = tup[0]
self.y = tup[1]
# retrieving attributes
def __getattr__(self, name):
if name == 'vector':
# returns the vector as a tuple
# (x, y)
return (self.x, self.y)
elif name == 'length' or name == 'magnitude':
# returns the length as a float
# sqrt(x^2 + y^2)
return float( sqrt(self.x**2 + self.y**2) )
elif name == 'normal':
# returns a normalized vector as a tuple
# (x/l, y/l)
if self.length == 0:
return (0, 0)
else:
x = self.x / self.length
y = self.y / self.length
return (x, y)
#return (self.x / self.length, self.y / self.length)
# setting attributes
def __setattr__(self, name, value):
if name == 'x' or name == 'y':
# assign value normally
self.__dict__[name] = value
elif name == 'length':
# |(x, y)| * length
# create a new, normalized vector of the same trajectory
new_vector = Vector(self.normal)
# then multiply it by a scalar to get the desired length
self.x = new_vector.x * value
self.y = new_vector.y * value
elif name == 'vector':
# does the same as setting both x and y at the same time
if len(value) == 2: # must be a list or tuple
self.x = value[0]
self.y = value[1]
# mathematical operations
def __add__(self, other):
# (x1 + x2, y1 + y2)
x = self.x + other.x
y = self.y + other.y
return Vector((x, y))
def __iadd__(self, other):
return self + other
def __sub__(self, other):
# (x1 - x2, y1 - y2)
x = self.x - other.x
y = self.y - other.y
return Vector((x, y))
def __isub__(self, other):
return self - other
Visual_vector class:
class Visual_vector(Vector):
"""A class to represent the vectors shown on screen"""
def __init__(self, origin, end_point):
# qualities relative to a coord system
Vector.__init__(self, end_point)
# qualities relative to the screen
self.origin = origin
self.end_point = end_point
Upvotes: 0
Views: 282
Reputation: 42778
You should not use such a __setattr__
-Method because of your observed wired behaviour. Replace it with a length
- or vector
-property
class Vector(object):
"""A class to represent a 2D vector"""
def __init__(self, tup):
self.x = tup[0]
self.y = tup[1]
# retrieving attributes
@property
def vector(self):
# returns the vector as a tuple
# (x, y)
return (self.x, self.y)
@vector.setter
def vector(self, value):
self.x = value[0]
self.y = value[1]
@property
def length(self):
# returns the length as a float
# sqrt(x^2 + y^2)
return float( sqrt(self.x**2 + self.y**2) )
magnitude = length
@length.setter
def length(self, value):
# |(x, y)| * length
# create a new, normalized vector of the same trajectory
x, y = self.normal
# then multiply it by a scalar to get the desired length
self.x = x * value
self.y = y * value
@property
def normal(self):
# returns a normalized vector as a tuple
# (x/l, y/l)
len = self.length
if len == 0:
return (0, 0)
else:
x = self.x / len
y = self.y / len
return (x, y)
# mathematical operations
def __add__(self, other):
# (x1 + x2, y1 + y2)
x = self.x + other.x
y = self.y + other.y
return Vector((x, y))
def __iadd__(self, other):
self.x += other.x
self.y += other.y
return self
def __sub__(self, other):
# (x1 - x2, y1 - y2)
x = self.x - other.x
y = self.y - other.y
return Vector((x, y))
def __isub__(self, other):
self.x -= other.x
self.y -= other.y
return self
class Visual_vector(Vector):
"""A class to represent the vectors shown on screen"""
def __init__(self, origin, end_point):
# qualities relative to a coord system
Vector.__init__(self, end_point)
# qualities relative to the screen
self.origin = origin
self.end_point = end_point
Upvotes: 1