Python: 2 classes importing each other causes an error? - python

So I have the following directory setup:
Project
Misc Packages and Modules
resources
shapes
Rectangle.py
Rectangle2D.py
Rectangle is just a conceptual rectangle that isn't ever drawn (using Tkinter) but is there for collision and bounds. Rectangle2D is used as a subclass to draw or fill a Rectangle. The classes before I got the error were as followed:
Rectangle.py
class Rectangle(object):
_x = -1
_y = -1
_w = -1
_h = -1
def __init__(self, x, y, w, h):
self._x = x
self._y= y
self._w = w
self._h = h
def intersects(self, other):
if isinstance(other, Rectangle):
if (self._x + self._w) > other._x > self._x and (self._y + self._h) > other._y > self._y:
return True
elif (self._x + self._w) > (other._x + other._w) > self._x and (self._y + self._h) > other._y > self._y:
return True
elif (self._x + self._w) > other._x > self._x and (other._y + other._h) > self._y > other._y:
return True
elif (self._x + self._w) > (other._x + other._w) > self._x and (other._y + other._h) > self._y > other._y:
return True
else:
return False
else:
return False
def __eq__(self, other):
return self._x == other._x and self._y == other._y and self._w == other._w and self._h == other._h
Rectangle2D.py
from tkinter import Canvas
from .Rectangle import Rectangle
class Rectangle2D(Rectangle):
def __init__(self, x, y, w, h):
super(Rectangle2D, self).__init__(x, y, w, h)
self.color = 'black'
self.id = None
def draw_rect(self, canvas):
if isinstance(canvas, Canvas):
self.id = canvas.create_rectangle(self._x, self._y, self._x + self._w, self._y + self._h, outline=self.color)
return True
else:
print("Improper Parameter Type")
return False
def fill_rect(self, canvas):
if isinstance(canvas, Canvas):
self.id = canvas.create_rectangle(self._x, self._y, self._x + self._w, self._y + self._h, fill=self.color)
return True
else:
print("Improper Parameter Type")
return False
Everything was working fine until I wanted to add a method to Rectangle.py that would return a Rectangle2D.py. This record the following line to be added to Rectangle.py in addition to the method:
from .Rectangle2D import Rectangle2D
This resulted in the following error:
from .Rectangle import Rectangle
ImportError: cannot import name 'Rectangle'
What is causing this error and how do I fix it?
Also note I am running Python 3.6

Related

Expected type tuple in function

My program implements a generic coerce_apply function that, given the name of an action and the two arguments as objects of types, units of measurement calculates and returns the result of the action on the arguments, by converting one of the objects to the type of the other object
Copy all the code to see the error that is in the key and I can not solve
class Centimeters(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return 'Centimeters({0})'.format(self.val)
class Inches(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return 'Inches({0})'.format(self.val)
class Feets(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return 'Feets({0})'.format(self.val)
def Inches_to_Centimeters(C):
return Centimeters(C.Inches*2.54)
def add_Centimeters(s,o):
return Centimeters('%.20f' % (s.val + o.val))
def add_Inches(s,o):
return Inches('%.20f' % (s.val + o.val))
def add_Inches_Centimeters(i,c):
return add_Inches(i,centimeter_to_inche(c))
def add_Centimeters_Inches(c, i):
return add_Centimeters(c, inche_to_centimeter(i))
def type_tag(x):
return type_tag.tags[type(x)]
type_tag.tags = {Centimeters: 'cen', Inches: 'inc', Feets: 'fee'}
centimeter_to_inche = lambda x: Centimeters(x.val * 1/2.54)
inche_to_centimeter = lambda x: Inches(x.val * 2.54)
coercions = {('inc', 'cen'): inche_to_centimeter}
def coerce_apply(operator_name, x, y):
tx, ty = type_tag(x), type_tag(y)
if tx != ty:
if (tx, ty) in coercions:
tx, x = ty, coercions[(tx, ty)](x)
elif (ty, tx) in coercions:
ty, y = tx, coercions[(ty, tx)](y)
else:
return 'No coercion possible.'
assert tx == ty
key = (operator_name, tx)
return coerce_apply.implementations[key](x, y)
coerce_apply.implementations = {}
coerce_apply.implementations[('add', ('inc', 'cen'))] = add_Inches_Centimeters
print(coerce_apply('add',Inches(1),Centimeters(150)))
Your approach is convoluted - normally you use classes to combine data with methods to allow f.e. the Centimeter class to handle its own conversion and addition to other units.
You get
File "t.py", line 46, in <module>
print(coerce_apply('add',Inches(1),Centimeters(150)))
File "t.py", line 43, in coerce_apply
return coerce_apply.implementations[key](x, y)
KeyError: ('add', 'cen')
because you are missing the conversion to add centimeters to centimerters in your code.
You can fix it like so (I removed Feets):
class Centimeters(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return 'Centimeters({0})'.format(self.val)
# enable self-addition by other centimeters
def __add__(self, other):
if not isinstance(other, Centimeters):
raise Exception("Bad __add__ call")
self.val += other.val
return Centimeters(self.val + other.val)
class Inches(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return 'Inches({0})'.format(self.val)
# enable self-addition by other Inches
def __add__(self, other):
if not isinstance(other, Inches):
raise Exception("Bad __add__ call")
return Inches(self.val + other.val)
def Inches_to_Centimeters(C):
return Centimeters(C.Inches*2.54)
def add_Centimeters(s,o):
return Centimeters('%.20f' % (s.val + o.val))
def add_Inches(s,o):
return Inches('%.20f' % (s.val + o.val))
def add_Inches_Centimeters(i,c):
return add_Inches(i,centimeter_to_inche(c))
def add_Centimeters_Inches(c, i):
return add_Centimeters(c, inche_to_centimeter(i))
def type_tag(x):
return type_tag.tags[type(x)]
type_tag.tags = {Centimeters: 'cen', Inches: 'inc', Feets: 'fee'}
centimeter_to_inche = lambda x: Centimeters(x.val * 1/2.54)
inche_to_centimeter = lambda x: Inches(x.val * 2.54)
coercions = {('inc', 'cen'): inche_to_centimeter}
def coerce_apply(operator_name, x, y):
tx, ty = type_tag(x), type_tag(y)
if tx != ty:
if (tx, ty) in coercions:
tx, x = ty, coercions[(tx, ty)](x)
elif (ty, tx) in coercions:
ty, y = tx, coercions[(ty, tx)](y)
else:
return 'No coercion possible.'
assert tx == ty
key = (operator_name, (tx,ty))
return coerce_apply.implementations[key](x, y)
coerce_apply.implementations = {}
coerce_apply.implementations[('add', ('inc', 'cen'))] = add_Inches_Centimeters
# add self-addition via classes __add__ method to "conversion"
coerce_apply.implementations[('add', ('cen', 'cen'))] = Centimeters.__add__
print(coerce_apply('add',Inches(1),Centimeters(150)))
Output:
Centimeters(152.54)

Problem using super().__init__() when doing class inheritance

I have this simple code to calculate the height and width of a rectangle defining 3 classes:
PointL which creates 1 point with x and y attributes.
Polyline: which just contains 4 points from the class Point.
Rectangle: which is supposed to call the points from Polyline and return the height and width.
However I'm getting 0.0 for both height and width all the time. I have to use the super() method for this.
class Point:
def __init__(self, x=0.0, y=0.0):
self.__x = x
self.__y = y
def set_x(self, x):
self.__x = x
def set_y(self, y):
self.__y = y
def set(self, x, y):
self.__x = x
self.__y = y
def get_x(self):
return self.__x
def get_y(self):
return self.__y
def __str__(self): # <---- New __str__ method
return "Point("+str(self.__x)+", "+str(self.__y)+")"
x = property(get_x, set_x)
y = property(get_y, set_y)
class Polyline:
def __init__(self, n=None):
self.__p0 = Point()
self.__p1 = Point()
self.__p2 = Point()
self.__p3 = Point()
self.__n = n
def get_p0(self):
return self.__p0
def get_p1(self):
return self.__p1
def get_p2(self):
return self.__p2
def get_p3(self):
return self.__p3
def set_p0(self, p):
self.__p0 = p
def set_p1(self, p):
self.__p1 = p
def set_p2(self, p):
self.__p2 = p
def set_p3(self, p):
self.__p3 = p
def __str__(self):
return "Line 1 from: " + str(self.__p0) + " to " + str(self.__p2) + "\n" + "Line 2 from: " + str(self.__p1) + " to " + str(self.__p3) + "\n"
p0 = property(get_p0, set_p0)
p1 = property(get_p1, set_p1)
p2 = property(get_p2, set_p2)
p3 = property(get_p3, set_p3)
class Rectangle(Point):
def __init__(self, n=None, height=0.0, width=0.0):
super().__init__(n) # <--- Call inherited constructor of Point-class
self.__height = height
self.__width = width
def get_height(self):
p0 = super().get_p0()
p1 = super().get_p1()
self.__height = p0.y - p1.y
def get_width(self):
p0 = super().get_p0()
p1 = super().get_p1()
self.__width = p0.x - p1.x
def __str__(self):
return "Rectangle dimensions: \n" + "Width: " + str(self.__width) + ", " + "Height: " + str(self.__height) + "\n"
width = property(get_width)
height = property(get_height)
These are my inputs:
polyline = Polyline()
polyline.p0.x = 0.0
polyline.p0.y = 2.0
polyline.p1.x = 3.0
polyline.p1.y = 4.0
print(polyline)
rectangle = Rectangle()
print(rectangle)
And these are my outputs:
Line 1 from: Point(0.0, 2.0) to Point(0.0, 4.0)
Line 2 from: Point(3.0, 4.0) to Point(3.0, 2.0)
Rectangle dimensions:
Width: 0.0, Height: 0.0

unable to fix this

I am trying to solve this problem . I am getting error . I can't understand where to fix
class Location(object):
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, deltaX, deltaY):
return Location(self.x + deltaX, self.y + deltaY)
def getX(self):
return self.x
def getY(self):
return self.y
def dist_from(self, other):
xDist = self.x - other.x
yDist = self.y - other.y
return (xDist ** 2 + yDist ** 2) ** 0.5
def __eq__(self, other):
return (self.x == other.x and self.y == other.y)
def __str__(self):
return '<' + str(self.x) + ',' + str(self.y) + '>'
class Campus(object):
def __init__(self, center_loc):
self.center_loc = center_loc
def __str__(self):
return str(self.center_loc)
class MITCampus(Campus):
""" A MITCampus is a Campus that contains tents """
def __init__(self, center_loc, tent_loc=Location(0, 0)):
""" Assumes center_loc and tent_loc are Location objects
Initializes a new Campus centered at location center_loc
with a tent at location tent_loc """
# Your code here
self.center_loc = center_loc
self.tent_loc = tent_loc
def add_tent(self, new_tent_loc):
""" Assumes new_tent_loc is a Location
Adds new_tent_loc to the campus only if the tent is at least 0.5 distance
away from all other tents already there. Campus is unchanged otherwise.
Returns True if it could add the tent, False otherwise. """
# Your code here
try:
self.tent_loc[object] += 1
except:
self.tent_loc[object] = 1
return new_tent_loc in self.tent_loc
def remove_tent(self, tent_loc):
""" Assumes tent_loc is a Location
Removes tent_loc from the campus.
Raises a ValueError if there is not a tent at tent_loc.
Does not return anything """
# Your code here
if tent_loc not in self.tent_loc:
return
self.tent_loc[tent_loc] -= 1
if self.tent_loc[tent_loc] < 1:
del (self.tent_loc[tent_loc])
For example, if c = MITCampus(Location(1,2)) then executing the following sequence of commands:
c.add_tent(Location(2,3)) should return True
c.add_tent(Location(0,0)) should return False
c.add_tent(Location(2,3)) should return False
c.get_tents() should return ['<0,0>', '<1,2>', '<2,3>']
i am getting is error : The class named 'MITCampus' should define a method named get_tents.
def add_tent(self, new_tent_loc):
""" Assumes new_tent_loc is a Location
Adds new_tent_loc to the campus only if the tent is at least 0.5 distance
away from all other tents already there. Campus is unchanged otherwise.
Returns True if it could add the tent, False otherwise. """
# Your code here
try:
self.tent_loc[object] += 1
except:
self.tent_loc[object] = 1
return new_tent_loc in self.tent_loc
This cannot work : object is a builtin that cannot be used as sequence index.
Finding a fast solution is faster than explaining everything ;)
class Location(object):
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, deltaX, deltaY):
return Location(self.x + deltaX, self.y + deltaY)
def getX(self):
return self.x
def getY(self):
return self.y
def dist_from(self, other):
xDist = self.x - other.x
yDist = self.y - other.y
dist = (xDist ** 2 + yDist ** 2) ** 0.5
return dist
def __eq__(self, other):
return (self.x == other.x and self.y == other.y)
def __str__(self):
return '<' + str(self.x) + ',' + str(self.y) + '>'
class Campus(object):
def __init__(self, center_loc):
self.center_loc = center_loc
def __str__(self):
return str(self.center_loc)
class MITCampus(Campus):
""" A MITCampus is a Campus that contains tents """
def __init__(self, center_loc, tent_loc=Location(0, 0)):
""" Assumes center_loc and tent_loc are Location objects
Initializes a new Campus centered at location center_loc
with a tent at location tent_loc """
# Your code here
assert isinstance(center_loc, Location)
assert isinstance(tent_loc, Location)
self.center_loc = center_loc
self.tent_locs = [tent_loc]
def add_tent(self, new_tent_loc):
""" Assumes new_tent_loc is a Location
Adds new_tent_loc to the campus only if the tent is at least 0.5 distance
away from all other tents already there. Campus is unchanged otherwise.
Returns True if it could add the tent, False otherwise. """
# Your code here
assert isinstance(new_tent_loc, Location)
added = False
for tent_loc in self.tent_locs:
if tent_loc.dist_from(new_tent_loc) <= 0.5:
break
else:
self.tent_locs.append(new_tent_loc)
added = True
return added
def remove_tent(self, tent_loc):
""" Assumes tent_loc is a Location
Removes tent_loc from the campus.
Raises a ValueError if there is not a tent at tent_loc.
Does not return anything """
# Your code here
assert isinstance(tent_loc, Location)
position = self.tent_locs.index(tent_loc)
del self.tent_locs[position]
def get_tents(self):
return sorted([str(x) for x in [self.center_loc] + self.tent_locs])
c = MITCampus(Location(1, 2))
assert c.add_tent(Location(2, 3)) # -> True
assert not c.add_tent(Location(0, 0)) # -> Flase
assert not c.add_tent(Location(2, 3)) # -> False
assert c.get_tents() == ['<0,0>', '<1,2>', '<2,3>']
try:
c.remove_tent(Location(6, 6))
print "removal failed"
except ValueError:
# Expected behaviour
pass
c.remove_tent(Location(2, 3))
assert c.get_tents() == ['<0,0>', '<1,2>']
Hope this helped ! Think to my reputation ;)

Create a picklable Python class

I am trying to create some custom Python classes for my application. When I try to debug my code I can not pick the instances of my custom classes, I receive the error "Object XXX is not picklable".
I found this page https://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled but I don't understand how I should implement the methods that make my class picklable.
For example how would you modify the following classes so that I can pick instances of them?
class Point3D:
def __init__ (self, x, y, z):
self.x = x
self.y = y
self.z = z
def move(self, vector):
self.x += vector.x
self.y += vector.y
self.z += vector.z
return
def isValidPoint(self):
isNotValid = False
isNotValid = math.isnan(self.x) or math.isnan(self.y) or math.isnan(self.z)
return not isNotValid
And
class PointCloud3D:
def __init__ (self):
self.points = []
def getNumberOfPoints(self):
return len(self.points)
def addPoint(self, point):
self.points.append(point)
return
def addPointCloud3D(self, additionalPointCloud3D):
for self.point in additionalPointCloud3D:
self.addPoint(point)
def getCloudCenter(self):
numberOfPoints = self.getNumberOfPoints()
centersSumX = 0
centersSumY = 0
centersSumZ = 0
for point in self.points:
centersSumX = centersSumX + point.x
centersSumY = centersSumY + point.y
centersSumZ = centersSumZ + point.z
centerX = centersSumX/numberOfPoints
centerY = centersSumY/numberOfPoints
centerZ = centersSumZ/numberOfPoints
center = Point3D(float(centerX), float(centerY) , float(centerZ))
return center
While here you can find the code that I am trying to debug:
from classDatabase import Point3D, PointCloud3D
testPoint1 = Point3D(1.5, 0.2, 2.3)
testPoint2 = Point3D(3.5, 1.2, 5.3)
testPointCloud3D = PointCloud3D()
testPointCloud3D.addPoint(testPoint1)
testPointCloud3D.addPoint(testPoint2)
Finally a screenshot of the issue:

Overriding the plus operator for a user defined vector class in Python

I have written a class to work with three dimensional vectors as follows
class vector(object):
def __init__(self, x=None, y=None, z=None, angle=None):
if angle == None:
self.x, self.y, self.z = x, y, z
if angle != None:
if angle == "rad":
self.r, self.theta, self.phi = x, y, z
if angle == "deg":
self.r = x
self.theta = y * 2 * pi / 360.
self.phi = z * 2 * pi / 360.
self.x = self.r * sin(self.theta) * cos(self.phi)
self.y = self.r * sin(self.theta) * sin(self.phi)
self.z = self.r * cos(self.theta)
def write(self):
file.write("[" + str(self.x) + ",\t" + str(self.y) + ",\t" + str(self.z) + "]")
def write_sph(self):
file.write("[" + str(self.mag()) + ",\t" + str(self.gettheta()) + ",\t" + str(self.getphi()) + "]")
def getx(self):
return self.x
def gety(self):
return self.y
def getz(self):
return self.z
def setx(self, x):
self.x = x
def sety(self, y):
self.y = y
def setz(self, z):
self.z = z
def square(self):
return self.x*self.x + self.y*self.y + self.z*self.z
def mag(self):
return sqrt(self.square())
def gettheta(self):
return arccos(self.z / self.mag())
def getphi(self):
return arctan2(self.y, self.x) # sign depends on which quadrant the coordinates are in
def __add__(self, vector(other)):
v_sum = vector(other.gettx() + self.gettx(), other.getty() + self.getty(), other.getty() + self.getty())
return v_sum
In the last definition I am attempting to override the operator for addition. The definition works by calling a new vector named other and adding its x,y,z components to the corresponding components of self. When I run the code I'm told the syntax for the definition is invalid. How do I correctly define the vector argument for this overriding definition? Also what difference would changing the definition from def __ add __ to simply def add make? i.e what do the underscores denote?
You shouldn't have vector(other) in your parameter list - just say other. Also, you'll need to fix the typos in the add method:
def __add__(self, other):
v_sum = vector(other.getx() + self.getx(), other.gety() + self.gety(), other.getz() + self.getz())
return v_sum

Categories

Resources