我正在学习Python中的继承机制,我想制作一些在子__init_()函数中自动计算的变量,但问题是我想要制作另一个变量将被覆盖的类。我不希望这些变量计算两次,一次在父级,然后在子级。那么,下面的例子是否正确?
class Shape(object):
def __init__(self, x, y):
self.x = x
self.y = y
def getcenter(self):
return self.x, self.y
class Square(Shape):
def __init__(self, x, y, a):
super().__init__(x,y)
self.a = a
self.perimeter = 4*a
self.field = a*a
class Rectangle(Square):
def __init__(self, x, y, a, b):
super().__init__(x, y, a)
self.perimeter = (2*a) + (2*b)
self.field = a*b
答案 0 :(得分:3)
好吧,忽略你的上面实际上有更好的Square子类Rectangle,通常这种类型的逻辑将被移动到由子类重写的新函数。
class Square:
def __init__(self, a):
self.a = a
self.calculate_perimeter()
def calculate_perimeter(self):
self.perimeter = self.a * 4
class Rectangle(Square):
def __init__(self, a, b):
self.b = b
super().__init__(a)
# automatically called by the parent class
def calculate_perimeter(self):
self.perimeter = self.a * 2 + self.b * 2
答案 1 :(得分:2)
我可以在这里想到几种不同的方法:
有人会问" Isn是一个矩形的特定情况吗?"
然后这应该有效,对吧?
class Rectangle(Shape):
def __init__(self, x, y, a, b):
super(Rectangle, self).__init__(x, y)
self.perimeter = (2 * a) + (2 * b)
self.field = a * b
class Square(Rectangle):
def __init__(self, x, y, a):
super(Square, self).__init__(x, y, a, a)
self.a = a
这样,您就可以获得使用a=a
和b=a
计算的周边和字段属性。 Square 的矩形。
另一个不错的选择是使用@property
装饰器,并动态计算周边和字段(乘以整数是一个非常便宜的操作)
class Shape(object):
def __init__(self, x, y):
self.x = x
self.y = y
def getcenter(self):
return self.x, self.y
class Square(Shape):
def __init__(self, x, y, a):
super(Square, self).__init__(x, y)
self.a = a
@property
def perimeter(self):
print("Perimeter of Square")
return 4 * self.a
@property
def field(self):
return self.a * self.a
class Rectangle(Square):
def __init__(self, x, y, a, b):
super(Rectangle, self).__init__(x, y, a)
self.b = b
@property
def perimeter(self):
print("Perimeter of Rectangle")
return (2 * self.a) + (2 * self.b)
@property
def field(self):
return self.a * self.b
if __name__ == "__main__":
s = Square(1, 2, 3)
r = Rectangle(5, 6, 7, 8)
print ("Perimeter (square) %s" % s.perimeter)
print ("Perimeter (rectangle) %s" % r.perimeter)
有关this great SO thread上的属性的更多信息。
还有更多!我建议你玩一些示例,看看你能做些什么(总的来说,你玩得很开心): - )
答案 2 :(得分:2)
您应该将它们作为属性实现,而不是制作perimeter
和field
属性。这样,它们只在被要求时计算。这也将防止在实例化类时必须计算这些值。
如前所述,从Rectangle继承Square非常有用。原则上,Square可能只是Rectangle的替代构造函数。虽然您可以根据使用情况选择不同的设计。
class Rectangle(Shape):
def __init__(self, x, y, a, b):
self.a = a
self.b = b
super().__init__(x, y)
@property
def perimeter(self):
return (self.a + self.b) * 2
class Square(Rectangle):
'''Just an alternate constructor for Rectangle'''
def __init__(self, x, y, a):
super().__init__(x, y, a, a) #b is same as a in a square.
#everything else already works!
示例:
>>> my_square = Square(0, 0, 10)
>>> my_square.perimeter
40
>>> my_rect = Rectangle(0,0, 10, 5)
>>> my_rect.perimeter
30
属性解决的另一个问题是用户不能错误地将周长设置为不同的值。
>>> my_square.perimeter = 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
否则,perimeter
将被允许设置,因此与a
和b
#without properties you could get inconsistent values
>>> my_square.perimeter = 10
>>> print(my_square.perimeter, my_square.a, my_square.b)
10 10 10
您还可以使用属性设置器来指示当有人尝试设置属性时会发生什么。
class Circle(object):
def __init__(self, radius):
self.radius = radius
@property
def diameter(self):
return self.radius * 2
@diameter.setter
def diameter(self, diam):
self.radius = diam / 2
例如:
>>> my_circle = Circle(radius=5)
>>> my_circle.diameter
10
>>> my_circle.diameter = 40
>>> my_circle.radius
20