Learning class in python but having issue that probably is simple - python

I have simple code that creates a rectangle
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
class Rectangle:
def __init__(self, posn, w, h):
self.corner = posn
self.width = w
self.height = h
def __str__(self):
return "({0},{1},{2})".format(self.corner, self.width, self.height)
box = Rectangle(Point(0, 0), 100, 200)
print("box: ", box)
The output of this code is
('box: ', <__main__.Rectangle instance at 0x0000000002368108>)
I expect the output to be
box: ((0, 0), 100, 200)
Can someone please help?

You don't define a __repr__() on your Rectangle class. Printing a tuple (as you are doing) uses the repr() of the class, not the str(). You also need a __str__() on your Point class.

You need to define __repr__ in both the Classes, like this
class Point(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __repr__(self):
return "({}, {})".format(self.x, self.y)
class Rectangle(object):
def __init__(self, posn, w, h):
self.corner = posn
self.width = w
self.height = h
def __repr__(self):
return "({0},{1},{2})".format(self.corner, self.width, self.height)
print "box: ", box
# box: ((0, 0),100,200)

It seems like you're using Python 2.x: In Python 2.x, print is statement, not a function.
By putting (...), you're printing str(("box:", box)). (A tuple containing a string and Rectangle object)
Remove parentheses, and define Point.__str__ to get what you expected.
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return str((self.x, self.y))
# OR return '({0.x}, {0.y})'.format(self)
class Rectangle:
def __init__(self, posn, w, h):
self.corner = posn
self.width = w
self.height = h
def __str__(self):
return "({0},{1},{2})".format(self.corner, self.width, self.height)
box = Rectangle(Point(0, 0), 100, 200)
print("box: ", box) # This prints a tuple: `str(("box: ", box))`
print "box: ", box # This prints `box: ` and `str(box)`.
output:
('box: ', <__main__.Rectangle instance at 0x00000000027BC888>)
box: ((0, 0),100,200)

Related

Use object from one class as attribute for another class

I am trying to make a circle which asks only for a center and radius. Here is my code:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print_point(self):
print(f"Point: {self.x, self.y}")
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {(self.center), self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()
What am I doing wrong?
You can assign the __repr__ method to your point class:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point: {self.x, self.y}"
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {((self.center)), self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()
It looks like you're not actually getting any info from the class that's being passed, and just trying to print the object itself. I haven't tested this code myself but try
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print_point(self):
print(f"Point: {self.x, self.y}")
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {((self.center.x),(self.center.y)), self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()
or use another function that returns the string to be printed:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def print_point(self):
print(f"Point: {self.x, self.y}")
def get_point(self):
return f'Point: {self.x, self.y}'
class Circle:
def __init__(self, center, radius):
self.center = center
self.radius = radius
def print_circle(self):
print(f"Circle: {self.center.get_point()},{self.radius}")
p1 = Point(150, 100)
c1 = Circle(p1, 75)
c1.print_circle()

Check if variable is defined in the superclass or subclass

This is just academic. Consider the following example:
class Shape():
def __init__(self, x, y):
self.x = x
self.y = y
def position(self):
return self.x, self.y
class Rectangle(Shape):
def __init__(self, x, y, height, width):
#super().__init__(x, y) # OK
self.x = x # not OK!
self.y = y # not OK!
self.height = height
self.width = width
r1 = Rectangle(1, 2, 3, 4)
If I asked someone to implement the class Rectangle, and they implemented with the "not OK" statements (instead of the with the "OK" statement as they should), then r1.x would be an attribute of Rectangle instead of Shape. Is there a way I can check if r1.x is a member of the Rectangle class or of the Shape class? Essentially, I want to make sure the initialization of the super class is being run, and no unnecessary new attributes are being created.

Calling a method from parent class that has a different name in the subclass

Having the following code:
class Point:
'class that represents a point in the plane'
def __init__(self, xcoord=0, ycoord=0):
''' (Point,number, number) -> None
initialize point coordinates to (xcoord, ycoord)'''
self.x = xcoord
self.y = ycoord
def setx(self, xcoord):
''' (Point,number)->None
Sets x coordinate of point to xcoord'''
self.x = xcoord
def sety(self, ycoord):
''' (Point,number)->None
Sets y coordinate of point to ycoord'''
self.y = ycoord
def get(self):
'''(Point)->tuple
Returns a tuple with x and y coordinates of the point'''
return (self.x, self.y)
def move(self, dx, dy):
'''(Point,number,number)->None
changes the x and y coordinates by dx and dy'''
self.x += dx
self.y += dy
def __repr__(self):
'''(Point)->str
Returns canonical string representation Point(x, y)'''
return 'Point('+str(self.x)+','+str(self.y)+')'
class Rectangle(Point):
def __init__(self,bottom_left,top_right,color):
self.get = bottom_left
self.get = top_right
self.color = color
def get_bottom_left(self,bottom_left):
print ()
r1 = Rectangle(Point(0,0), Point(1,1), "red")
r1.get_bottom_left()
I want to be able to print "Point(0,0)" by calling self__rep__(self) from class Point from the method get_bottom_left, but I just have no idea how. I know how to use inheritance if the functions have the same name, but in this case I am stuck and it is a requirement for the child function to have the method names it has. If it looks that I am just looking for the answer, I would like the response to just explain me a similar case of this application please!
When I do the following:
class Rectangle(Point):
def __init__(self,bottom_left,top_right,color):
self.get = bottom_left
self.get = top_right
self.color = color
def get_bottom_left(self,bottom_left):
print (self.bottom_left)
I get: get_bottom_left() missing 1 required positional argument: 'bottom_left'
As mentioned in the comment, Rectangle should contain Point instances and not inherit Point. If you change Rectangle class as shown below, you'll see the expected result:
class Rectangle():
def __init__(self, bottom_left, top_right, color):
self.bottom_left = bottom_left
self.top_right = top_right
self.color = color
def get_bottom_left(self):
print self.bottom_left

Comparing variables within classes in python

I'm trying to write a method(it) that compares the size (area) of the rectangle with the area of another rectangle passed as a parameter:
class Rectangle:
def __init__(self, x, y):
self.width = x
self.height = y
def area(self):
a = self.width * self.height
return a
def __it__(self,second):
return self.area < second.area
But I keep getting error:
TypeError: unorderable types: Rectangle() < Rectangle()
I'm not to sure how to fix this problem
You had a typo. It's __lt__, not __it__, and you need to call the area() as a function unless you set that as a property.
Fixing all that...
>>> class Rectangle:
... def __init__(self, x, y):
... self.width = x
... self.height = y
... def area(self):
... a = self.width * self.height
... return a
... def __lt__(self,second):
... return self.area() < second.area()
...
>>> Rectangle(1,3) > Rectangle(4,5)
False
Area is a method, you're using it as though it's a variable. Adding parens should fix it (and if you're trying to do less than, it should be __lt__):
def __lt__(self, second):
return self.area() < second.area()

Python: Calling class method instead of parent constructor

Say I have the following class definition:
class WorldObject(pygame.sprite.Sprite):
#classmethod
def fromImgRect(cls, rect, image, collideable = True):
return cls(rect.left, rect.top, rect.width, rect.height, image, collideable)
def __init__(self, x, y, w, h, image, collideable = True):
self.rect = pygame.rect.Rect(x,y,w,h)
self.collideable = collideable
self.image = image
Then I have the following child class:
class Doodad(WorldObject):
def __init__(self,c1x, c1y, c2x, c2y, color = (200,0,180)):
self.color = color
self.rect = orderPoints(c1x, c1y, c2x, c2y)
x1 = self.rect.left
y1 = self.rect.top
w = self.rect.width
h = self.rect.height
super(Doodad, self).__init__(x1,y1,w,h,self.surface, False)
This works just fine, however it is annoying to have to unpack self.rect like this all throughout my code, instead of just doing it once in the class method. This is happening in many places throughout my project, where several of my methods return a rectangle object, but I need to pass coordinates to a super constructor. It doesn't look like its possible to have everything return either coordinates or a rectangle, sometimes it just makes more sense to do one or the other. Since python doesn't support overloading methods, I'd like to be able to use the class method to initialize the object. However I haven't been able to figure out the syntax. Is this possible? If so, how?
In your situation, I would add a method for "sub-initializing". This would post-process the given data:
class WorldObject(pygame.sprite.Sprite):
#classmethod
def fromImgRect(cls, rect, *a, **k):
return cls(rect.left, rect.top, rect.width, rect.height, *a, **k)
def __init__(self, x, y, w, h, image, collideable=True):
self._init_coords(x, y, w, h)
self.collideable = collideable
self.image = image
def _init_coords(self, x, y, w, h):
self.rect = pygame.rect.Rect(x,y,w,h)
Then you can have the following child class:
class Doodad(WorldObject):
def _init_coords(self, c1x, c1y, c2x, c2y):
self.rect = orderPoints(c1x, c1y, c2x, c2y)
def __init__(self,c1x, c1y, c2x, c2y, color=(200, 0, 180)):
super(Doodad, self).__init__(c1x, c1y, c2x, c2y, self.surface, False)
self.color = color
Besides, you might want to have
def unpack_rect(rect):
return rect.left, rect.top, rect.width, rect.height
You can even have
class WorldObject(pygame.sprite.Sprite):
def __init__(self, *a, **k):
if hasattr(a[0], 'left'):
rect = a[0]
self._init_coords(rect.left, rect.top, rect.width, rect.height)
rest = a[1:]
else:
self._init_coords(*a[0:4])
rest = a[4:]
self._init_rest(*rest, **k)
def _init_coords(self, x, y, w, h):
self.rect = pygame.rect.Rect(x,y,w,h)
def _init_rest(self, image, collideable=True):
self.collideable = collideable
self.image = image
class Doodad(WorldObject):
def _init_coords(self, c1x, c1y, c2x, c2y):
self.rect = orderPoints(c1x, c1y, c2x, c2y)
def _init_rest(color=(200, 0, 180)):
super(Doodad, self)._init_rest(self.surface, False)
self.color = color
(I didn't change self.surface here, but it is not defined at this moment. You should change that.)

Categories