26.面向对象的三个基本特征之继承
面向对象的三个基本特征是:继承、多态,封装。这里讲继承。
继承:是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类由称为基类或超类,新建的类称为派生类或子类
查看父类:类名.__banses__ 可以查看该类的父类
如果一个类没有继承任何类,使用类名.__banses__ 返回的是class 'object'(对象类) 在python3中,一个类没有继承任何父类,就默认继承class 'object'(对象类)
单继承:
使用继承: class 子类名(父类名) 就可以在子类中使用父类的属性
class animal: def __init__(self,name,kind): self.name=name self.kind=kind def eat(self): print('%s正在吃'%self.name) def drink(self): print('%s正在喝'%self.name) def look_door(self): print('%s正在看门'%self.name) class Dog(animal): def look_door(self): print('%s正在看门'%self.name) class Bird(animal): def egg(self): print('%s正在下蛋'%self.name) wangwang=Dog('大黄','金毛') jiji=Bird('星期五','鹦鹉') jiji.egg() #调用自己类的方法 wangwang.look_door() #调用自己类的方法
执行结果:
星期五正在下蛋
大黄正在看门
子类中的方法与父类中的方法同名,当子类自己有方法时,就不会去父类中寻找方法,被调用时会使用子类自己的方法。
派生:在父类属性之外又添加属于自己类的属性
如果子类和父类都拥有__init__()方法,子类就无法继承父类中的__init__(),只调用自己的__init__()
因此想要继承父类的__init__(),还想添加属于自己类的属性,
就要在子类__init__()中引用父类的__init__(),代码如下:
class Animal: def __init__(self,name,kind): self.name=name self.kind=kind def eat(self): print('%s正在吃'%self.name) def drink(self): print('%s正在喝'%self.name) class Dog(Animal): def __init__(self,name,kind,high): Animal.__init__(self,name,kind) #引用父类的__init__() self.high=high #派生属性,添加属于自己类的方法 def look_door(self): #派生方法,父类没有而子类有的方法 print('%s正在看门'%self.name) s=Dog('大黄','金毛','50cm') print(s.high)
派生属性:父类中没有的属性,在子类中出现,就叫做派生属性
派生方法:父类中没有的方法在子类中出现
class Animal: def __init__(self,name,kind): self.name=name self.kind=kind def eat(self): print('%s正在吃'%self.name) def drink(self): print('%s正在喝'%self.name) class Dog(Animal): def drink(self): Animal.drink(self) #调用子类中的函数,注意参数一定是self print('这是新添加的父类没有的语句') #子类函数新添加的语句 s=Dog('大黄','金毛') s.drink()
只要是子类的对象调用 ,子类中有的名字,一定用子类的,子类中没有才找父类的
在子类函数中调用父类函数的方法,同时又给方法添加新属性;不仅能使用父类中的函数,还能使用自己拓展的属性
super
在上面的代码中,子类中有__init__() ,且父类中也有__init__(),想让子类使用父类中的__init__,就可以使用:
父类名.__init__(self,父类的属性名)
这样子类就可以使用父类中的属性。
还可以使用super关键字来完成此功能。具体格式为:super().__init__(name,kind)
如果在子类中使用super()方法,就意为这去找父类的方法,使用super就可以找到父类,区别就是不用传递self作为参数
代码如下:
class Animal: def __init__(self,name,kind): self.name=name self.kind=kind def eat(self): print('%s正在吃'%self.name) def drink(self): print('%s正在喝'%self.name) class Dog(Animal): def __init__(self,name,kind,high): super().__init__(name,kind) #使用super引用父类的__init__(),参数与父类__init__的参数相同 self.high=high def drink(self): print('%s正在喝'%self.name) s=Dog('大黄','金毛','50cm') print(s.high)
super只在新式类中有(在pyhton3中所有的类都是新式类)
super不仅可以在类里使用,也可以在类外使用:super(Dog,s).drimk() 就可以执行到父类中的drink方法(super(Dog,s)可以找到Dog类的父类,然后执行drink方法)
super的本质:在多继承中,不是单纯的找父类,而是根据调用者的节点位置的广度优先顺序来的
多继承:
一个类继承多个类就是多继承。如下:类D继承了ABC多个类
class A: def func(self): print('a') class B: def func(self): print('b') class C: def func(self): print('c') class D(A,B,C): def func(self): print('d') d=D() d.func()
执行结果:
d (D中有自己的func()方法,因此函数的执行结果为d)
class A: def func(self): print('a') class B: def func(self): print('b') class C: def func(self): print('c') class D(A,B,C): pass d=D() d.func()
执行结果:
a (该段代码中,类D中没有自己的func()方法,就需要使用所继承的父类中的func(),因为类A写在最前面,因此有限执行类A的func()方法,代码最后打印A)
钻石继承问题:
如果两个类所继承的类相同,先广度寻找,再深度寻找;继承的类不相同,就先深度寻找,再广度寻找。
多继承中,子类的对象调用一个方法,默认就是就近原则,找的顺序为:
新式类中,类的继承顺序采用的是广度优先算法
标准类中,类的继承顺序采用的是深度优先算法
在python2.7中,新式类与经典类共存,新式类要继承object,Python3中,只有新式类,默认继承object
类名.mro() 使用该语句可以查看该类所继承的父类的寻找顺序, mro方法只在新式类中存在