继承和多态
类可以继承自基类,也可以被子类继承,比如Animal继承自object类,而自身又可以被Dog和Cat类继承
1 2 3 4 5 6 7 | class Animal( object ): def run( self ): print ( 'Animal is running' ) class Dog(Animal): pass class Cat(Animal): pass |
继承的子类拥有了基类的全部属性和方法,而且子类还可以在基类的基础上新增属性或者方法,如下代码在子类中重写了初始化函数,因此子类初始化就按自己定义的初始化函数进行,但是下面的代码在printscore报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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,导致调用失败。通过本例理解了__打头的变量就连自己的子类都无法调用。
上例正确的用法应该是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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类:
1 2 3 4 5 6 7 8 | 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)) |
子类可以覆盖基类的方法和属性,如果一个函数的参数为基类,我们就可以传入子类作为参数,因为子类属于基类,而且函数并不因为传入了子类而需要修改,对于一个变量,我们只需要知道它的基类,而具体的细节由它具体的子类来决定。允许新增子类,而不需要修改依赖该基类的函数。
比如以下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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函数即可,这就叫鸭子类型,看起来像鸭子,走起来像鸭子就可以了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步