添加from_tuple()类方法,允许使用元组创建对象?

时间:2017-12-09 05:32:51

标签: python python-3.x

Circle类使用Point对象作为中心。需要一个名为from_tuple的@classmethod来允许使用元组而不是Point作为中心来创建Circle对象。 This is how the output should look like for from_tuple()

我为凌乱的代码道歉,有两个吸气剂和一个中心的二传手。我知道中心必须是一个元组,我真的很困惑。请帮助我在访问from_tuple()时解决getter中的AttributeError问题。

错误信息如下所示

>>> center_point=3,4
>>> circle=Circle.from_tuple(center=center_point)
>>> circle
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\hole1\Desktop\ProgramIntro\shapes.py", line 54, in __repr__
    return "Circle(center=Point({0}, {1}), radius={2})".format(self.center[0],self.center[1],self.radius)
  File "C:\Users\hole1\Desktop\ProgramIntro\shapes.py", line 65, in center
    return(self._center)
AttributeError: 'Circle' object has no attribute '_center'

以下是课程点:

 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)   

以下是班级圈。

 class Circle(Point):
        def __init__(self, center=(0,0), radius=1):
            try:
                x, y = center
                super(Circle, self).__init__(x,y)
                Point.__init__(self,center)
                self.radius=radius
                self.center=center
            except (UnboundLocalError, TypeError, AttributeError) as e:
                    pass
            if not center == (0,0):
                if not isinstance(center,Point):
                    if not isinstance(center, tuple):
                        raise TypeError("The center must be a oint!")
        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)
        @property
        def center(self):
            return self.x, self.y
        @property
        def center(self):
            return(self._center)
        @center.setter
        def center(self, center):
            if not center == (0,0):
                if not isinstance(center,Point):
                    raise TypeError("The center must be a Point!")
            self._center=center
        @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
        @classmethod
        def from_tuple(cls, center=(0,0),radius=1):
            return cls(center,radius)

1 个答案:

答案 0 :(得分:1)

你的代码中有很多错误的东西 - 从逻辑(即为什么Circle继承自Point?)到结构(使用未声明的实例属性) )彻头彻尾的怪异(为什么你要两次定义你的Circle.center吸气剂?) - 但是这个错误的主要罪魁祸首是捕获所有异常只是为了忽略它们的非常糟糕的想法,因为如果你还没有这样做,你自己会注意到错误。

即,当您调用Circle.from_tuple()类方法时,它会依次创建一个新的Circle实例,并通过传递的__init__()和{center方法调用其radius方法{1}}(顺便说一句。为什么在您转发论据时需要Circle.from_tuple() - 为什么不直接拨打Circle()?)。鉴于您已将(3, 4)作为center传递给它,它就好像您已有效地呼叫:Circle.__init__(center=(3, 4))

你会遇到很多问题。首先,您调用super.__init__()方法传递中心xy - 公平地说,它会启动self.xself.y和{ {1}}(多余的,但不要进入它)。然后由于某种未知原因,您尝试再次调用它,使用不同的语法并仅将您的元组作为第一个参数传递,而现在又将self.data变为self.x的值{{1 }})。但真正的问题在于你打电话给你的center setter传递相同的(3, 4)元组。如果你看一下你的方法:

Circle.center()

您认为会发生什么?鉴于传递的(3, 4)@center.setter def center(self, center): if not center == (0, 0): if not isinstance(center, Point): raise TypeError("The center must be a Point!") self._center = center )不是center,而且绝大多数都不是(3, 4)的实例(它是一个元组),它会引发{(0, 0)将永远不会设置1}}和Point

但是等等,因为您已经决定捕获TypeError中的所有self._centerUnboundLocalErrorTypeError例外情况,只是通过它们就永远不会得到通知您的AttributeError未设置,所以当您尝试在REPL中打印出来时Circle.__init__()会被调用,而后者又会尝试访问未定义的center并获得您的好处错误。

快速&amp;肮脏的解决方案,因为您已经从Circle.__repr__()继承,只是完全忘记了中心 - 您已经Circle._centerPoint(和self.x是基于这些的列表)所以删除对self.y的任何引用,你就是黄金:

self.data

现在,您可以使用centerclass Circle(Point): def __init__(self, center=(0, 0), radius=1): super(Circle, self).__init__(*center) self.radius = radius def __str__(self): return "Circle with center at ({0}, {1}) and radius {2}".format(self.x, self.y, self.radius) def __repr__(self): return "Circle(center=Point({0}, {1}), radius={2})".format(self.x, self.y, self.radius) @property def center(self): return Point(self.x, self.y) @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 对其中心进行实例化。

但更好的解决方案是重新考虑你想在这里实现什么,当你遇到困难时,尝试使用好的旧Rubber duck debugging来捕获错误,例如代码中的错误。