4.5 继承
面向对象的编程带来的好处之一是代码的重用,实现这种重用方法之一是通过继承 机制。继承是两个类或多个类之间的父子关系,子类继承了基类的所有公有数据属性和方法,并且可以通过编写子类的代码扩充子类的功能。开个玩笑地说,如果人类可以做到儿女继承了父母的所有才学并加以拓展,那么人类的发展至少是现在的数万倍。继承实现了数据属性和方法的重用,减少了代码的冗余度。
那么我们何时需要使用继承呢?如果我们需要的类中具有公共的成员,且具有一定的递进关系,那么就可以使用继承,且让结构最简单的类作为基类。一般来说,子类是父类的特殊化,如下面的关系:
哺乳类动物——>狗——>特定狗种
特定狗种类继承狗类,狗类继承哺乳动物类,狗类编写了描述所有狗种公有的行为的方法而特定狗种类则增加了该狗种特有的行为。不过继承也有一定弊端,可能基类对于子类也有一定特殊的地方,如某种特定狗种不具有绝大部分狗种的行为,当程序员没有理清类间的关系时,可能使得子类具有了不该有的方法。另外,如果继承链太长的话,任何一点小的变化都会引起一连串变化,我们使用的继承要注意控制继承链的规模。
继承语法:class子类名(基类名1,基类名2,…)基类写在括号里,如果有多个基类,则需要全部都写在括号里,这种情况称为多继承 。在Python中继承有以下一些特点:
1)在继承中基类初始化方法__init__不会被自动调用。如果希望子类调用基类的__init__方法,需要在子类的__init__方法中显示调用了它。这与C++和C#区别很大。
2)在调用基类的方法时,需要加上基类的类名前缀,且带上self参数变量。注意在类中调用该类中定义的方法时不需要self参数。
3)Python总是首先查找对应类的方法,如果在子类中没有对应的方法,Python才会在继承链的基类中按顺序查找。
4)在Python继承中,子类不能访问基类的私有成员。
我们最后一次修改类Charmander的代码,如代码清单4-6所示:
代码清单4-6 自定义类5
class pokemon: def __init__(self,name,gender,level,type,status): self.__type = type self.__gender = gender self.__name = name self.__level = level self.__status = status self.__info = [self.__name,self.__type,self.__gender,self.__level, self.__status] self.__index = -1 def getName(self): return self.__name def getGender(self): return self.__gender def getType(self): return self.__type def getStatus(self): return self.__status def level_up(self): self.__status = [s+1 for s in self.__status] self.__status[0]+=1 # HP每级增加 2点,其余 1点 def __iter__(self): print '名字 属性 性别 等级 能力 ' return self def next(self): if self.__index ==len(self.__info)-1: raise StopIteration self.__index += 1 return self.__info[self.__index] class Charmander(pokemon): def __init__(self,name,gender,level): self.__type = ('fire',None) self.__gender = gender self.__name = name self.__level = level # 最大 HP,攻击,防御,特攻,特防,速度 self.__status = [10+2*level,5+1*level,5+1*level,5+1*level,5+1*level,5+1* level] pokemon.__init__(self,self.__name,self.__gender,self.__level,self.__type, self.__status)
*代码详见:示例程序/code/4-5.py
>>> pokemon1 = Charmander('Bang','male',5) >>> print pokemon1.getGender() male >>> for info in pokemon1: print info Bang ('fire', None) male 5 [20, 10, 10, 10, 10, 10]
我们定义了Charmander类的基类pokemon,将精灵共有的行为都放到基类中,子类仅仅需要向基类传输数据属性即可。这样做可以很轻松地定义其他基于pokemon类的子类。因为精灵宝可梦的精灵有数百只,使用继承的方法大大减少了代码量,且当需要对全部精灵进行整体修改时仅需修改pokemon类即可。可以看到我们Charmander类的__init__函数中显示调用了pokemon类的__init__函数,并向基类传输数据,这里注意要加self参数。Charmander类没有继承基类的私有数据属性,因此在子类中只有一个self.__type,不会出现因继承所造成的重名情况。为了能更清晰地讲述这个问题,这里再举一个例子,如代码清单4-7所示:
代码清单4-7 私有成员无法继承
class animal: def __init__(self,age): self.__age = age def print2(self): print self.__age class dog(animal): def __init__(self,age): animal.__init__(self,age) def print2(self): print self.__age a_animal = animal(10) a_animal.print2() #result: 10 a_dog = dog(10) a_dog.print2() # 程序报错, AttributeError: dog instance has no attribute '_dog__age'
*代码详见:示例程序/code/4-5.py
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论