0

The Circle class takes Point object as the center of circle. To verify the center of the circle instance is a Point object, I added an if not isinstance() statement in init. This if statement raises TypeError when center is not a Point object.

def __init__(self, center=(0,0), radius=1):
        Point.__init__(self,center)
        self.center=center
        self.radius=radius
        if not isinstance(center,Point):
            raise TypeError("The center must be a Point!")

However, the code seems to accept any tuple in the form of (x,y) to be Point object. Is there a way to only pass the Point object to be center and anything else any tuple to be TypeError?

The desired output is shown in the following:

>>> circle  =   Circle(center=4,    radius=1.5) 
[Traceback...] 
TypeError:  The center  must    be  a   Point!
>>> circle  =   Circle(center=Point(3,4),   radius=2) 
>>> circle.center   =   (3, 4) 
[Traceback...] 
TypeError:  The center  must    be  a   Point!

The following is the code for Point class:

import math
class Point:
    def __init__(self,x=0,y=0):
        self.x = x
        self.y = y
        self.data=[x,y]
    def __getitem__(self, index):
        return self.data[index]
    def __iter__(self):
        yield self.x
        yield self.y
    def __add__(self,other):
        return Point(self.x+other.x,self.y+other.y) 
    def __mul__(self,n):
        return Point(self.x*n,self.y*n) 
    def __rmul__(self,n):
        return Point(n*self.x,n*self.y) 
    @classmethod
    def from_tuple (cls, self=(0,0)):
        return cls(*self)   
    def loc_from_tuple(self,t=(0,0)):
        self.x=t[0]
        self.y=t[1] 
    def __str__(self):
        return "Point at ({0}, {1})".format(self.x,self.y)  
    def __repr__(self):
        return"Point(x={0}, y={1})".format(self.x,self.y)   

The following is class Circle

class Circle(Point):
    def __init__(self, center=(0,0), radius=1):
        Point.__init__(self,center)
        self.center=center
        self.radius=radius
        if not isinstance(center,Point):
            raise TypeError("The center must be a Point!")

    def __getitem__(self,item):
        return self.center[item]
    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)
    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

This is what I am getting.

Koko. N
  • 47
  • 5
  • 1
    Look at this : https://stackoverflow.com/questions/9305751/force-ensure-python-class-attributes-to-be-of-specific-type – Rahul Bharadwaj Dec 08 '17 at 13:10
  • 1
    https://stackoverflow.com/questions/27074942/reusing-validation-logic-in-setter-and-constructor-the-right-way https://stackoverflow.com/questions/2825452/correct-approach-to-validate-attributes-of-an-instance-of-class – Josh Lee Dec 08 '17 at 13:11
  • You're doing validation on the radius... why aren't you doing it on the center? – glibdud Dec 08 '17 at 13:15
  • You've got the check for class Point in your initial constructor, so you check for and flag the assignment when you are CREATING the circle. The second time, you're not creating a new circle but rather updating an existing circle. So the constructor is not used, so the situation is not flagged. You would need a method for updating the value of `center`, and in that method you would need to check the class type of what's passed in. – GaryMBloom Dec 08 '17 at 13:21

1 Answers1

1

Here what's happening in your code. When you create a circle with a center=Point (a Point object), your code create a Point with a Point as argument in center since you wrote

Point.__init__(self,center) # center is a Point object which is not what you want

This is not in accordance with the default value of center (which is a tuple), when you instantiate the Circle object with no center this will not work since the tuple center will not pass

isinstance(center,Point)

To use the inheritance, do as follow (also, not verifying that center is a tuple make more sense) :

class Circle(Point):
    def __init__(self, center=(0,0), radius=1):
        x, y = center
        super(Circle, self).__init__(x, y)
        self.center = center # This is not useful
        self.radius = radius
        if not isinstance(center, tuple):
            raise TypeError("The center must be a tuple!")

    @property
    def center(self): # This if a better way to access the center
        return(self.x, self.y)
Grundoc
  • 131
  • 9
  • x,y=center doesn't look right...Will this cause another kind of typeError, saying that integer is not iterated ? – Koko. N Dec 08 '17 at 15:47
  • It will work fine, in python you can do stuff like x,y=(0,0) or x,y,z=(0,0,0), etc. Also you can verify if x,y are integer to make your code more safe. – Grundoc Dec 18 '17 at 09:10