概念
一个类拥有另外一个类的资源的方式之一
并不是资源的复制,变成双份资源,而是资源的使用权
资源指非私有的属性和方法
分类
单继承
class Animal:
pass
class Dog(Animal):
pass
多继承
class Animal:
pass
class xxx:
pass
class Dog(Animal, xxx):
pass
查看父类:
class Animal:
pass
class xxx:
pass
class Dog(Animal, xxx):
pass
print(Dog.__bases__)
(<class ‘main.Animal’>, <class ‘main.xxx’>)
type 与 object 区别
class Animal:
pass
class xxx:
pass
class Dog(Animal, xxx):
pass
print(Dog.__bases__)
print(Animal.__bases__)
print(int.__bases__)
print(float.__bases__)
print(bool.__bases__)
d = Dog()
print(d.__class__)
print(Dog.__class__)
print(type.__class__)
(<class ‘main.Animal’>, <class ‘main.xxx’>)
(<class ‘object’>,)
(<class ‘object’>,)
(<class ‘object’>,)
(<class ‘int’>,)
<class ‘main.Dog’>
<class ‘type’>
<class ‘type’>
继承对资源的影响
在python中,继承是指资源的使用权。所以,测试某个资源能否被继承,其实就是测试在子类中能不能访问到父类中的这个资源
除了私有的属性和私有的方法,其他的基本都能继承。
继承内容:
- 公有属性、方法
- 受保护的属性、方法
- 内置方法
class Animal:
# 属性 和 方法
# 设置不同权限的属性和方法,继承当中,进行测试
# 在子类当中,能否访问到这些资源
a = 1 # 公有的
_b = 2 # 受保护的
__c = 3 # 私有的
def t1(self):
print('t1')
def _t2(self):
print('t2')
def __t3(self):
print('t3')
def __init__(self):
print('init, Animal')
class Person(Animal):
def test(self):
print(self.a)
print(self._b)
# print(self.__c)
self.t1()
self._t2()
# self.__t3()
self.__init__()
p = Person()
p.test()
Animal.a = 666
p.test()
init, Animal
1
2
t1
t2
init, Animal
666
2
t1
t2
init, Animal
class B():
age = 10
class A(B):
pass
print(A.age)
A.age = 9
print(B.age)
print(A.__dict__)
print(B.__dict__)
10
10
{‘module’: ‘main’, ‘doc’: None, ‘age’: 9}
{‘module’: ‘main’, ‘age’: 10, ‘dict’: <attribute ‘dict’ of ‘B’ objects>, ‘weakref’: <attribute ‘weakref’ of ‘B’ objects>, ‘doc’: None}
继承的几种形态
- 单继承链
- 无重叠的多继承链
- 有重叠的多继承链
单继承:遵循从下到上的原则,自己身上没有这个资源,就到父类里面去找。
无重叠的多继承链:遵循单调原则,按照继承的先后顺序,优先调用左侧的继承链
有重叠的多继承链:遵循重下到上的原则
概念补充
MRO: Method Resolution Order, 方法解析顺序
深度优先
沿着一个继承链,尽可能往深处查找
具体算法步骤:
- 把根节点压入栈中
- 每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中
- 重复第2个步骤到结束为止
广度优先
沿着继承链,尽可能往宽了去找。
具体算法步骤:
- 把根节点放到队列的末尾
- 每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把他们放到队列的末尾,发现已经被处理则略过。
- 重复上面步骤
C3 算法
两个公式:
L(object) = [object]
L(子类(父类1, 父类2)) = [子类] + merge(L(父类1), L(父类2), [父类1, 父类2])
+ 代表合并列表
merge 算法:
- 第一个列表的第一个元素,是后续列表的第一个元素,或者,后续列表中没有再次出现,则将这个元素合并到最终的解析列表中,并从当前的操作的所有列表中删除。
- 如果不符合,则跳过此元素,查找下一个列表的第一个元素,重复1的判断规则。
- 如果最终无法把所有元素归并到解析列表,则报错
类似拓扑排序,但并不是
python 2.2之前
仅存在经典类,MRO原则为深度优先(从左往右),问题为有重叠的多继承,违背重写可用原则
python2.2
产生了新式类,MRO原则,经典类为深度优先(从左往右)。新式类为在深度优先(从左往右)的算法基础上,优化了一部分,如果产生重复元素,会保留最后一个,并且更尊重基类出现的先后顺序。注意,并不是广度优先算法
问题:
- 无法检测出有问题的继承
- 有可能还会违背局部优先的原则
python2.3 -2.7
新式类经典类并存
MRO原则:经典类为深度优先()从左到右。新式类为C3原则。
python 3.x
只有新式类
MRO原则:C3算法
查看继承方式
- inspect.getmro(A)
- A.mro()
- A.__mro__
import inspect
class C():
age = 'c'
class B(C):
age = 'b'
class A(B):
age = 'a'
print(inspect.getmro(A))
print(A.mro())
print(A.__mro__)
(<class ‘main.A’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘object’>)
[<class ‘main.A’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘object’>]
(<class ‘main.A’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘object’>)
资源的覆盖
属性的覆盖
方法的重写
import inspect
class D(object):
age = 'd'
class C(D):
age = 'c'
def test(self):
print('c')
class B(D):
age = 'b'
def test(self):
print('b')
class A(B, C):
pass
print(A.mro())
print(A.age)
print(A().test())
[<class ‘main.A’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘main.D’>, <class ‘object’>]
b
b
None
资源的累加
在一个类的基础之上,增加一些额外的资源(属性和方法)
子类相比于父类,对一些自己特有的资源
在被覆盖的方法之上,新增内容
class B():
a = 1
def __init__(self):
self.b = 2
def t1(self):
print("t1")
@classmethod
def t2(cls):
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
pass
a_obj = A()
print(A.a)
print(a_obj.b)
a_obj.t1()
A.t2()
A.t3()
1
2
t1
t2
t3
方案1:通过类名调用父类方法
class B():
a = 1
def __init__(self):
self.b = 2
def t1(self):
print("t1")
@classmethod
def t2(cls):
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
def __init__(self):
B.__init__(self)
self.xxx = "124"
a_obj = A()
print(a_obj.__dict__)
{‘b’: 2, ‘xxx’: ‘124’}
产生的问题:
class D(object):
def __init__(self):
print("d")
class B(D):
def __init__(self):
D.__init__(self)
print("b")
class C(D):
def __init__(self):
D.__init__(self)
print("c")
class A(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
print("a")
A()
d
b
d
c
a
方案2:super
在低优先级类的方法中,通过super调用高优先级类的方法
super是一个类,只有在新式类中有效
起着代理的作用,帮我们完成以下任务,沿着MRO链条,找到下一级节点,去调用对应的方法
语法原理:
super(参数1[, 参数2])
工作原理:
def super(cls, inst):
mro = inst.__class.mro()
return mro[mro.index(cls) + 1]
沿着谁的MRO链条?参数2
找谁的下一个节点?参数1
如何应对类方法,静态方法以及实例方法的传参问题?使用参数2进行调用
class B():
def __init__(self):
self.b = 2
self.xxx = "xxx"
def t1(self):
print("t1")
@classmethod
def t2(cls):
print("t2")
@staticmethod
def t3():
print("t3")
class A(B):
def __init__(self):
super().__init__()
self.e = "666"
def tt1(self):
print("tt1")
@classmethod
def tt2(cls):
super(A, A).t2()
print("tt2")
@staticmethod
def tt3():
print("tt3")
a = A()
print(a.__dict__)
A.tt2()
{‘b’: 2, ‘xxx’: ‘xxx’, ‘e’: ‘666’}
t2
tt2
class D(object):
def __init__(self):
print("d")
class B(D):
def __init__(self):
super().__init__()
print("b")
class C(D):
def __init__(self):
super().__init__()
print("c")
class A(B, C):
def __init__(self):
super().__init__()
print("a")
A()
d
c
b
a