面向对象:继承
定义:新建的一个类继承另外一个类,另外一个类称为父类,也称为基类或超类。新建的类称为派生类或者子类
作用:减少代码的重复性,提高可读性,规范编程方式
继承分为新式类和经典类,又分为单继承和新继承
经典类:python2当中默认为经典类,继承object后为新式类
新式类:python3当中只有新式类,默认继承object,拥有方法mro,用于解析类的执行顺序
单继承:直接找父类
多继承:钻石继承最为经典,在经典类中,钻石继承为深度优先,而在新式类中,为广度优先。
广度优先:新式类
深度优先:经典类
派生:子类在父类的方法和属性的基础上产生了新的属性和方法,称为派生属性和派生方法
单继承:
class A: pass class B(A): pass
多继承:
class A: pass class B: pass class C(A,B): pass
例:
# 下方的人狗大战,代码重复性太高,人是动物,狗是动物,他们有相同的属性,这时则可以创建一个动物类,让人和狗继承这个类,即动物为父类,人和狗为子类。 class Person: def __init__(self,name,hp,aggr,sex): self.name = name self.hp = hp self.aggr = aggr self.sex = sex def kick(self,dog): dog.hp -= self.aggr return '%s踢了狗%s,狗剩余%s血'%(self.name,dog.name,dog.hp) class Dog: def __init__(self,name,hp,aggr,sex): self.name = name self.hp = hp self.aggr = aggr self.sex = sex def bite(self,person): person.hp -= self.aggr return '狗%s咬了%s,人剩余%s血'%(self.name,person.name,person.hp) aike = Person('aike',1000,100,'男') chenfan = Dog('chenfan',500,50,'taddy') print(aike.kick(chenfan)) print(chenfan.bite(aike))
使用继承后:
class Animal: #父类,基类,超类 def __init__(self,name,hp,aggr,sex): self.name = name self.hp = hp self.aggr = aggr self.sex = sex class Person(Animal): #子类,派生类 def kick(self,dog): dog.hp -= self.aggr return '%s踢了狗%s,狗剩余%s血'%(self.name,dog.name,dog.hp) class Dog(Animal): #子类,派生类 def bite(self,person): person.hp -= self.aggr return '狗%s咬了%s,人剩余%s血'%(self.name,person.name,person.hp) aike = Person('aike',1000,100,'男') chenfan = Dog('chenfan',500,50,'taddy') print(aike.kick(chenfan)) print(chenfan.bite(aike))
单继承,派生属性、派生方法、super方法:
class Animal: #父类,基类,超类 ,python当中所有父类默认继承object类 def __init__(self,name,hp,aggr,sex): self.name = name self.hp = hp self.aggr = aggr self.sex = sex def func1(self): print('测试super') class Person(Animal): #子类,派生类 def __init__(self,name,hp,aggr,sex,money): #人要有钱这个属性 # Animal.__init__(self,name,hp,aggr,sex) # super().__init__(name,hp,aggr,sex)#super,等同于上一句的类调用,但是不用传self,因为在类的内部使用super方法,默认找父类,不用填写参数,等同于下面一句代码 super(Person,self).__init__(name,hp,aggr,sex)#括号内为自己的类名 self.money = money #钱属于派生属性 def kick(self,dog): #派生方法 dog.hp -= self.aggr return '%s踢了狗%s,狗剩余%s血'%(self.name,dog.name,dog.hp) def person_weapon(self,weapon): #获取武器 if (self.money - weapon.price) > 0: self.money -= weapon.price self.weapon = weapon self.aggr += weapon.aggr else: return '赶紧充钱' class Dog(Animal): #子类,派生类 def bite(self,person): #派生方法 person.hp -= self.aggr return '狗%s咬了%s,人剩余%s血'%(self.name,person.name,person.hp) class Weapon: #用钱可以买武器 def __init__(self,name,price,aggr): self.name = name self.price = price self.aggr = aggr def func(self): pass aike = Person('aike',1000,100,'男',1000) chenfan = Dog('chenfan',500,50,'taddy') stick = Weapon('stick',200,50) aike.person_weapon(stick)#装上武器+50攻击 print(aike.kick(chenfan)) print(chenfan.bite(aike)) print(aike.money) #装上武器,钱减少 super(Person,aike).func1()#在类外部使用需要传子类名和对象,调用方法时,只能调用父类的方法。
结论:
1、父类中没有的属性 在子类中出现 叫做派生属性
2、父类中没有的方法 在子类中出现 叫做派生方法
3、只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
4、super方法:只在新式类中才有,作用是调用父类的方法,与父类名调用方法的作用相同,但是父类名调用需传self。
在类中使用不用填参数,默认找父类,不用传self
在类外部使用需要传子类名和对象,调用方法时,只能调用父类的方法。
多继承:
#钻石继承1 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()
python3当中只有新式类,调用顺序遵循广度优先: D-->B-->C-->A
#钻石继承2 class A: def func(self): print('这是A') class B(A): def func(self): print('这是B') class E: def func(self): print('这是E') class C(E): def func(self): print('这是C') class D(B,C): def func(self): print('这是D') d = D() d.func() print(D.mro())#[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>]
python3当中只有新式类,调用顺序遵循广度优先: D-->B-->A-->C-->E
#钻石排列3 class A: def func(self): print('这是A') class B(A): def func(self): print('这是B') class C(A): def func(self): print('这是C') class E(B): def func(self): print('这是E') class F(C): def func(self): print('这是F') class D(E,F): def func(self): print('这是D') d = D() d.func() print(D.mro())#[<class '__main__.D'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
python3当中只有新式类,调用顺序遵循广度优先: D-->E-->B-->F-->C-->A
经典类为深度优先:即一条路找到低,找不到则换一条路。
关于super:
class A: def func(self): print('这是A') class B(A): def func(self): super().func() print('这是B') class C(A): def func(self): super().func() print('这是C') class D(B,C): def func(self): super().func() print('这是D') d = D() d.func() #打印为: 这是A 这是C 这是B 这是D
super的本质:不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的,所以寻找顺序为D-->B-->C-->A