继承是类与类之间的关系, 什么是什么
总结对象之间的相似点成类
总结类之间的相似点成父类
类从(子)下到(父)上,是抽象。类从上到下,是继承,类到对象实例化。
# class ParentClass1:
# pass
#
# class ParentClass2:
# pass
#
# class SubClass1(ParentClass1):
# pass
#
# class SubClass2(ParentClass1,ParentClass2):
# pass
#
# print(SubClass1.__bases__)
# print(SubClass2.__bases__)
class Hero:
x=3
def __init__(self,nickname,life_value,aggresivity):
self.nickname=nickname
self.life_value=life_value
self.aggresivity=aggresivity
def attack(self,enemy):
enemy.life_value-=self.aggresivity
class Garen(Hero):
# x=2
pass
class Riven(Hero):
pass
g1=Garen('刚们',29,30)
# print(g1.nickname,g1.life_value,g1.aggresivity)
# g1.x=1
print(g1.x)
#属性查找小练习
class Foo:
def f1(self):
print('from Foo.f1')
def f2(self):
print('from Foo.f2')
self.f1() #b.f1() 继续从对象本身开始找
class Bar(Foo):
def f1(self):
print('from Bar.f1')
b=Bar()
# print(b.__dict__)
b.f2()
输出:
from Foo.f2
from Bar.f1
属性查找: 先从对象自己这里查找,没有再去类里去找,类再没有,去父类找。
派生:
子类可以添加自己新属性或者在自己这里重新定义这些属性(不会影响父类),
需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新的属性时,就以自己为准了。
class Hero:
def __init__(self,nickname,life_value,aggresivity):
self.nickname=nickname
self.life_value=life_value
self.aggresivity=aggresivity
def attack(self,enemy):
enemy.life_value-=self.aggresivity
class Garen(Hero):
camp='Demacia'
def attack(self,enemy):
print('from Garen Class')
class Riven(Hero):
camp='Noxus'
g=Garen('草丛伦',100,30)
r=Riven('锐雯雯',80,50)
# print(g.camp)
# g.attack(r)
# print(r.life_value)
g.attack(r)
继承的实现原理:
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1. 子类会先于父类检查
2 多个父类会根据它们在列表中的顺序被检查
3 如果下一个类存在两个合法的选择,选择第一个父类
新式类中每个类都有一个mro方法。可以查出继承的顺序。
但经典类没有mro这个方法。
如:f = F()
print(f.__mro__) #只有新式类才有
在Java和C#中子类中能继承一个父类,而Python中子类可以同时继承多个父类,如果继承了多个父类,那么属性的查找方式有两种,分别是:深度优先和广度优先。
Python2中有分经典类和新式类。Python3都是新式类。
python2中 经典类: 没有继承object类以及子类,都称为经典类。这个类的子类也叫经典类。
class Foo:
pass
class Bar(Foo):
pass
python2:新式类: 继承了object类以及子类,都称为新式类。
class Foo(object):
pass
class Bar(Foo):
pass
print(Bar.__base__)
Python3:默认都继承了object类
class Foo():
pass
print(Foo.__base__)
输出:<class: object>
当类是经典类时,多继承情况下,在要查找属性不存在时,会按照深度优先的方式查找下去。
#验证多继承情况下的属性查找
class A:
# def test(self):
# print('from A')
pass
class B(A):
# def test(self):
# print('from B')
pass
class C(A):
# def test(self):
# print('from C')
pass
class D(B):
# def test(self):
# print('from D')
pass
class E(C):
# def test(self):
# print('from E')
pass
class F(D,E):
# def test(self):
# print('from F')
pass
#F,D,B,E,C,A
print(F.mro())
# f=F()
# f.test()
实验:如果C没有继承A,新式类会不会是F D B A E C ??
在子类中重用父类的方法
在子类派生出的新的方法中重用父类的方法,有两种实现方式
方式一:指名道姓(不依赖继承)
方式二:super() (依赖继承)
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是调用普通函数的方式,即:类名.func(),此时就与调用函数无异了,因此即便是self参数也要为其传值 。
方式一示例:
class Hero:
def __init__(self,nickname,life_value,aggresivity):
self.nickname=nickname
self.life_value=life_value
self.aggresivity=aggresivity
def attack(self,enemy):
enemy.life_value-=self.aggresivity
class Garen(Hero):
camp='Demacia'
def __init__(self,nickname,life_value,aggresivity,weapon):
# self.nickname=nickname
# self.life_value=life_value
# self.aggresivity=aggresivity
Hero.__init__(self,nickname,life_value,aggresivity) #也是指名道姓,不依赖继承
self.weapon=weapon
def attack(self,enemy):
Hero.attack(self,enemy) #指名道姓,不依赖于继承。如果没有继承Hero也是可以的。
print('from Garen Class')
g=Garen('草丛伦',100,30,'金箍棒')
print(g.__dict__)
方式二示例:
class Hero:
# def __init__(self,nickname,life_value,aggresivity):
# self.nickname=nickname
# self.life_value=life_value
# self.aggresivity=aggresivity
# def attack(self,enemy):
# enemy.life_value-=self.aggresivity
#
#
# class Garen(Hero):
# camp='Demacia'
#
# def __init__(self,nickname,life_value,aggresivity,weapon):
# # self.nickname=nickname
# # self.life_value=life_value
# # self.aggresivity=aggresivity
#
# # super(Garen,self).__init__(nickname,life_value,aggresivity) #python2
# super().__init__(nickname,life_value,aggresivity) #python3可以这样简写
# self.weapon=weapon
#
# def attack(self,enemy):
# super(Garen,self).attack(enemy) #依赖继承, super(Garen,self)是对象,所以self参数不用传。
# print('from Garen Class')
#
#
# g=Garen('草丛伦',100,30,'金箍棒')
#
# print(g.__dict__)
super()沿着MRO列表,是基于调用对象的MRO往后找。而不是调用对象本身再开始找。
class A:
def f1(self):
print('from A')
super().f1() #c对象有MRO往后找。
class B:
def f1(self):
print('from B')
class C(A,B):
pass
print(C.mro())
#[<class '__main__.C'>,
# <class '__main__.A'>,
# <class '__main__.B'>,
# <class 'object'>]
c=C()
c.f1()
输出:
from A
from B