继承¶
我们对面向对象编程的讨论的最后一个话题就是继承(inheritance)的概念。使用继承将提供强大的抽象概念和优雅的代码重运用——它允许某类继承另外一类的属性并以其为基础增加额外的功能。
让我们立刻考虑一个使用继承的例子。让我们重新讨论在本模组介绍中编写的 Rectangle
类。
class Rectangle:
""" 一类描述长方形特征的Python对象"""
def __init__(self, width, height, center=(0, 0)):
self.width = width
self.height = height
self.center = center
def __repr__(self):
return "Rectangle(width={w}, height={h}, center={c})".format(h=self.height,
w=self.width,
c=self.center)
def compute_area(self):
return self.width * self.height
现在,假设我们也想编写一个 Square
类,使得用户只需提供一个变长就能决定其大小。注意,正方形只是一种特殊的长方形而已——它的长和宽相同。在注意到这一点后,我们应该利用为 Rectangle
编写的代码。我们可以定义一个为 Rectangle
子类(subclass)的 Square
类。这意味着 Square
将会继承 Rectangle
的所有属性,包括它的方法。让我们来编写这个子类:
# 创建 Square,Rectangle 的子类
class Square(Rectangle):
def __init__(self, side, center=(0, 0)):
# 等值于 `Rectangle.__init__(self, side, side, center)`
super().__init__(side, side, center)
编写 class Square(Rectangle)
将会标示 Square
是 Rectangle
的子类,并因此会使其继承 Rectangle
的属性。接下来,请注意,我们重写了 Square
继承的 __init__
;与其接受一个高和宽,Square
应该通过提供单个边长描述。在这个新的 __init__
方法中,我们将收到的单个边长为左 Rectangle.__init__
中的长和宽输入。super
永远引用着某一类的“父类”或“超类”(super class),因此 super
在这里指 Rectangle
。
定义完我们的子类后,我们可以直接使用 Rectangle
的其它方法。让我们看看 Square
是如何工作的:
# 创建一个边长为 2 的正方形
>>> my_square = Square(2)
# 使用继承的 `get_area` 方法
>>> my_square.get_area()
4
# 正方形是一个有着相同长宽的长方形
>>> my_square
Rectangle(width=2, height=2, center=(0.0, 0.0))
>>> my_square.width == my_square.height
True
内置的 issubclass
函数允许我们确定 Square
和 Rectangle
之间的关系。
# `Square` 和 `Rectangle` 是不同的类
>>> Square is not Rectangle
True
# `Square` 是 `Rectangle` 的子类
>>> issubclass(Square, Rectangle)
True
# `my_square` 同时是 `Square` 和 `Rectangle` 实例
>>> isinstance(my_square, Square)
True
>>> isinstance(my_square, Rectangle)
True
继承总结¶
一般而言,如果你有类 A
,那么你可以通过以下定义子类 A
:
class A:
attr = 0
def method(self):
return 0
# `B` 是 `A` 的子类
class B(A):
# 继承 `attr` 和 `method`
b_attr = -2 # 和 `B` 不同的类属性
def method(self):
# 重写继承的 `method`
return -1
B
将会继承 A
的所有属性和方法。在 B
中定义属性和方法将重写 A
中已经存在的同名属性。B
也可以随意定义属于它自己的不同属性和方法,并和 A
无关。
>>> issubclass(B, A)
True
>>> A.attr
0
>>> A().method()
0
>>> B.attr
0
>>> B().method()
-1
>>> B.b_attr
-2
我们仅仅摸到了类继承这一话题的皮毛。虽然如此,本节向读者展示了类继承的基本功能和用法。