面向对象—继承(Day19)
初识继承
继承是一种创建新类的方式,在python中新类可以继承一个或多个父类,父类又可称为基类或超类,新建的类为派生类或子类。(类与类之间的关系是什么是什么的关系。)
继承语法:
class Parent:pass class Son(Parent):pass #Son继承了Parent print(Son.__bases__) #(<class '__main__.Parent'>,) print(Parent.__bases__) #(<class 'object'>,)
内置属性:__bases__用来查看当前类的父类是谁
在python3中所有的类都会默认继承object类,继承了object类的所有类都是新式类,如果一个类没有继承任何父类,那么__bases__属性就会显示(<class 'object'>,)。
继承分为单继承和多继承:
单继承:继承一个父类,所有面向对象语言都有单继承的特点。
多继承:可以继承多个父类。
class Parent1:pass class Parent2:pass class Parent3:pass class Son(Parent1,Parent2,Parent3):pass #Son继承了多个父类 print(Son.__bases__) #(<class '__main__.Parent1'>, <class '__main__.Parent2'>, <class '__main__.Parent3'>)
实例:
class Animal:#定义一个父类 def __init__(self,name,hp,ad): # 共有的属性 self.name = name self.hp = hp self.ad = ad class Person(Animal): #定义一个子类,继承父类 pass class Dog(Animal):#定义一个子类,继承父类 pass alex = Person('alex',10,20) teddy = Dog('teddy',50,60) print(alex.__dict__) print(teddy.__dict__)
派生:子类可以添加自己新的属性,或者在自己这里重新定义这些属性,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己的为准。
class Animal:#定义一个父类 def __init__(self,name,hp,ad): # 共有的属性 self.name = name self.hp = hp self.ad = ad class Person(Animal): #定义一个子类,继承父类 def attack(self,dog): #子类自己的属性,派生方法 print('%s攻击了%s' % (self.name,dog.name)) class Dog(Animal):#定义一个子类,继承父类 def bite(self,person): #子类自己的属性,派生方法 print('%s咬了%s' % (self.name,person.name)) alex = Person('alex',10,20) teddy = Dog('teddy',50,60) alex.attack(teddy) #alex攻击了teddy teddy.bite(alex) # ddy咬了alex
class Animal:#定义一个父类 def __init__(self,name,hp,ad): # 共有的属性 self.name = name self.hp = hp self.ad = ad def eat(self): print('%s吃药回血了' %self.name) class Person(Animal): #定义一个子类,继承父类 def attack(self,dog): #子类自己的属性,派生方法 print('%s攻击了%s' % (self.name,dog.name)) def eat2(self): print('执行了person类的eat方法') self.money = 100 self.money -= 10 self.hp += 10 class Dog(Animal):#定义一个子类,继承父类 def bite(self,person): #子类自己的属性,派生方法 print('%s咬了%s' % (self.name,person.name)) alex = Person('alex',10,20) teddy = Dog('teddy',50,60) teddy.eat() #teddy吃药回血了 alex.eat2() alex.eat() #alex吃药回血了
alex.eat = '123'
print(alex.eat())#对象自己内存空间里有了eat,不找类及父类中的
对象使用名字的顺序:先找对象自己内存空间里的,再找对象自己类内存空间里的,再找父类例的。
self.名字的时候,不要看self当前在哪个类里,要看这个self到底是谁的对象。
class Parent: def func(self): print('in parent func') def __init__(self): self.func() class Son(Parent): def func(self): print('in son func') s = Son() #in son func
object类:新式类默认继承object
继承与派生
1.在类中增加派生属性的方法:
父类名.__init__(属性名),
super(类名,self).__init__(属性名,不加self),可以简化成super()..__init__(属性名,不加self),在单继承中,super负责找到当前类所在的父类,在这个时候不需要再手动传self。
2.调用派生方法时子类中有找子类的,子类中没有找父类的,子类中有但是想要找父类中的有两种方法:
1)父类名.方法名(子类对象)
2)super(子类名,子类对象).方法() 这种方法一般不用,一般在子类内用super()
class Animal: def __init__(self,name,hp,ad): self.name = name # 对象属性 属性 self.hp = hp #血量 self.ad = ad #攻击力 def eat(self): print('eating in Animal') class Person(Animal): def __init__(self,name,hp,ad,sex): # Animal.__init__(self,name,hp,ad) super().__init__(name,hp,ad) # super(Person,self).__init__(name,hp,ad) self.sex = sex # 派生属性 def attack(self,dog): # 派生方法 print("%s攻击了%s"%(self.name,dog.name)) def eat(self): super().eat() #找父类里的方法 print('eating in Person') class Dog(Animal): def __init__(self,name,hp,ad,kind): Animal.__init__(self,name,hp,ad)# 类名.方法名 self.kind = kind def bite(self,person): # 派生方法 print("%s咬了%s" % (self.name, person.name)) # 人 sex alex = Person('alex',100,10,'female') # 实例化 teddy = Dog('tom',200,50,'泰迪') print(alex.__dict__) print(teddy.__dict__) Animal.eat(alex)#指名道姓法 super(Person,alex).eat() alex.eat()
钻石继承
新式类多继承顺序:广度优先的算法,保证每个类都能找一遍
class A: def func(self): print('A') class B(A): def func(self): print('B') class C(A): def func(self): print('C') class D(B,C): def func(self): print('D') d = D() d.func()
super在单继承中就是单纯的寻找父类
在多继承中就是根据当前模型所在的位置按照广度优先的算法找下一个类。
经典类多继承顺序:深度优先算法
经典类:在python2x版本中存在,且不继承object类,遍历时遵循深度优先的算法,没有mro方法,没有super方法。
新式类:python3x版本中只有新式类,python2x版本中需要继承object的才是新式类,遍历时遵循广度优先的算法,有super方法,但是在2.X版本的解释器中,必须传参数(子类名,子类对象),有mro方法。