继承和多态

类可以继承自基类,也可以被子类继承,比如Animal继承自object类,而自身又可以被Dog和Cat类继承

class Animal(object):
    def run(self):
        print('Animal is running')
class Dog(Animal):
  pass
class Cat(Animal):
  pass  

继承的子类拥有了基类的全部属性和方法,而且子类还可以在基类的基础上新增属性或者方法,如下代码在子类中重写了初始化函数,因此子类初始化就按自己定义的初始化函数进行,但是下面的代码在printscore报错

class Student(object):
    def __init__(self,name,score):
        self.__name=name
        self.__score=score
    
    def printscore(self):
        print('%s\'s score is %s'%(self.__name,self.__score))
        
class Junior(Student):
    def __init__(self,name,score,sex,height,weight):
        self.__name=name
        self.__score=score
        self.__sex=sex
        self.__height=height
        self.__weight=weight
    def printstudent(self):
        print('%s %s %s %s %s'%(self.__name,self.__score,self.__sex,self.__height,self.__weight))
class Master(Student):
    pass

kimi=Junior('kimi',100,'M',180,65)
kimi.printscore()
kimi.printstudent()

报错的原因在于Junior重写了初始化函数,因此Junior的实例中__name被更名为_Junior__name,而Student中的__name被更名为_Student__name,而printscore中调用的是_Student__name,导致调用失败。通过本例理解了__打头的变量就连自己的子类都无法调用。

上例正确的用法应该是  

class Student(object):
    def __init__(self,name,score):
        self.name=name
        self.score=score
    
    def printscore(self):
        print('%s\'s score is %s'%(self.name,self.score))
        
class Junior(Student):
    def __init__(self,name,score,sex,height,weight):
        self.name=name
        self.score=score
        self.sex=sex
        self.height=height
        self.weight=weight
    def printstudent(self):
        print('%s %s %s %s %s'%(self.name,self.score,self.sex,self.height,self.weight))
class Master(Student):
    pass

kimi=Junior('kimi',100,'M',180,65)
kimi.printscore()
kimi.printstudent()

还可以这么定义Junior类:

class Junior(Student):
    def __init__(self,name,score,sex,height,weight):
        Student.__init__(self,name,score)#或者使用super(Junior,self).__init__(self,name,score)
        self.sex=sex
        self.height=height
        self.weight=weight
    def printstudent(self):
        print('%s %s %s %s %s'%(self.name,self.score,self.sex,self.height,self.weight))

 子类可以覆盖基类的方法和属性,如果一个函数的参数为基类,我们就可以传入子类作为参数,因为子类属于基类,而且函数并不因为传入了子类而需要修改,对于一个变量,我们只需要知道它的基类,而具体的细节由它具体的子类来决定。允许新增子类,而不需要修改依赖该基类的函数。

比如以下的代码: 

class Student(object):
    def __init__(self,name,score):
        self.name=name
        self.score=score    
    def printscore(self):
        print('%s\'s score is %s'%(self.name,self.score))
    def printstudent(self):
        print('I am a Student')
class Junior(Student):
    def __init__(self,sex,height,weight):
        self.sex=sex
        self.height=height
        self.weight=weight
    def printstudent(self):
        print('I am a Junior student')

def printtwice(xtudent):
    xtudent.printstudent()
    xtudent.printstudent()

printtwice(Junior('M','180','65'))

printtwice函数接受Student类型的对象,因为Junior又是Student的子类,所以可以传入Junior的实例,但是printtwice函数却不需要进行修改。

这里在定义printtwice函数时传入的参数是xtudent,这里并未要求它是Student类型的对象,只要xtudent包含printstudent函数即可,这就叫鸭子类型,看起来像鸭子,走起来像鸭子就可以了。  

 

  

 

 

 

  

 

posted on 2017-06-02 22:41  vonkimi  阅读(241)  评论(0编辑  收藏  举报

导航