继承是面向对象设计的重要思想,其核心是代码的复用和程序功能高度的扩展性。继承在词典中的解释是把前人的知识、文化、思想、财产、知识等接受过来。在面向对象中,继承是对类而言的,新类可以继承已有类的属性和方法,这样做的好处是新类可以复用原有类所有的代码,复用的同时又可以定义新的方法和属性来扩展原有类的功能。
认识类的继承
为了理解类的继承,下面看一个案例。
某出版机构准备要通过微信小程序实现产品在微信媒体的推广和销售,出版机构的产品包括图书、音频、视频,图书又分为纸书和电子书。现在需要设计产品类,该类能够存储出版社所有产品的属性(如名称、价格、作者、摘要等产品信息),并能输出产品的属性。
由案例内容分析可知,该出版机构有纸质图书、电子图书、音频、视频产品,每类产品既有共同属性,如名称、价格、作者、摘要等属性。也有个性化属性,如纸质图书有字数、页数等属性,视频有分辨率、播放时长、文件大小、编码等属性,音频有采样频率、文件大小、编码等属性。电子图书有格式、文件大小等属性。
前面了解了抽象和封装,可以把同类事物的共同属性抽取出来形成类,既然该出版机构的纸质图书、电子图书、视频、音频产品都具有名称、价格、作者、摘要这些共同属性,可以创建一个Product产品类,代码如下:
#声明产品类
class Product:
#构造方法
def __init__(self,name,price,author,summary):
self.name = name
self.price = price
self.author = author
self.summary = summary
#输出产品属性
def outProduct(self):
print("产品名称:%s" % (self.name))
print("产品价格:%f" % (self.price))
print("产品作者:%s" % (self.author))
print("产品摘要:%s" % (self.summary))
Product类声明了该出版机构产品所具有的共同属性,有名称、价格、作者和摘要,并定义了输出产品属性的方法outProduct()。为了简单起见,上面的代码没有给出类属性的设置或获取方法,也没有显示定义类属性。
Product类并没有完全实现任务要求,因为该类的属性并没有全部反映出该出版机构所有产品的属性,如纸质图书、电子图书、视频、音频产品的个性化属性。
如何解决这个问题呢,有两种解决方案,一种解决方案是为每类产品都创建一个类,该类包含该产品的所有属性,即分别定义纸质图书类、电子图书类、视频类和音频类,鉴于篇幅关系下面仅给出纸质图书类的代码:
#定义图书类
class PaperBook:
#构造方法
def __init__(self,name,price,author,summary,words,pageNumbers):
self.name = name
self.price = price
self.author = author
self.summary = summary
self.words = words;
self.pageNumbers = pageNumbers
#输出产品属性
def outProduct(self):
print("图书名称:%s" % (self.name))
print("图书价格:%f" % (self.price))
print("图书作者:%s" % (self.author))
print("图书摘要:%s" % (self.summary))
print("图书字数:%s" % (self.summary))
print("图书页数:%s" % (self.pageNumbers))
例子代码仅给出了纸质图书类的代码,电子图书类、视频类和音频类可参照纸质图书类代码创建。这样创建的代码也可以完成案例任务要求,问题是创建的四个产品类中都有重复的属性和方法,代码重复,不符合面向对象的设计原则。
另外一种解决方案就是采用Python的类继承机制,利用Python的类继承机制可以让纸质图书类,电子图书类、视频类和音频类均继承于Product类,被继承的Product称为父类(所有子类的父类称为基类),继承的纸质图书类,电子图书类、视频类和音频类称为子类(子类也称为派生类),子类继承父类的所有属性和方法,同时子类可以声明自己特有的属性和方法。下图给出了出版机构的产品类继承图。

在Python中子类继承父类是通过在子类名称后面添加父类名称来实现的。下面给出纸质图书类的代码,其它子类代码请自行创建:
#定义Product类
#Product类继承object类
class Product(object):
#构造方法
def __init__(self,name,price,author,summary):
self.name = name
self.price = price
self.author = author
self.summary = summary
#输出产品属性
def outProduct(self):
print("产品名称:%s" % (self.name))
print("产品价格:%f" % (self.price))
print("产品作者:%s" % (self.author))
print("产品摘要:%s" % (self.summary))
#定义纸质图书类,纸质图书类继承于Product类
class PaperBook(Product):
#构造方法
def __init__(self,name,price,author,summary,words,pageNumbers):
Product.__init__(self,name,price,author,summary)
self.words = words
self.pageNumbers = pageNumbers
#输出图书产品属性
def outProduct(self):
print("图书名称:%s" % (self.name))
print("图书价格:%f" % (self.price))
print("图书作者:%s" % (self.author))
print("图书摘要:%s" % (self.summary))
print("图书字数:%s" % (self.words))
print("图书页数:%s" % (self.pageNumbers))
在上面的代码中,Product 类继承于object类。object类是Python的一个基类,Python所有的类都继承于Objec类。
Python的自定义类都会继承object类,即使没有显示继承,自定义类也会默认继承object类。
PaperBook类是Product类的子类,继承了Product类的全部属性,并重写了outProduct()方法。Product类是PaperBook类的父类。Python解释器在实例化PaperBook对象时,需要在PaperBook类的构造函数中调用父类的构造方法以初始化父类的数据。
图中的EBook类、Video类和Audio类都是电子类出版物,这些电子类出版物都具有共同的属性formation和filesize,可以把formation和filesize提取出来抽象为一个新的电子出版物类,电子图书类、视频类、音频类继承电子出版物类,电子出版物类又继承于产品类,从而构成产品类的层次结构,产品类层次结构如下图所示:

类的层次结构充分体现了面向对象编程的继承思想,高度抽象出的事物(Product类)再不断细化为接近现实的事物(PaperBook类和EProduct类),EProduct类又可以细化为具体事物(EBook、Video、Audio类),层层继承,高度复用了已有代码。
类的继承思想是也是一种系统设计思想,系统从高度抽象入手构建基础抽象类(基类),基础抽象类满足系统所有类的基本属性和操作要求。所有系统类均继承于基础抽象类,继承的系统类又可以被更具体化的子类继承,从而构成了系统的类层次结构。