420 lines
9.2 KiB
Markdown
420 lines
9.2 KiB
Markdown
# 类的继承
|
||
|
||
## 面向对象的继承
|
||
|
||
不用继承创建对象
|
||
|
||
```python
|
||
class Person:
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
|
||
class Cat:
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
|
||
class Dog:
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
```
|
||
|
||
使用继承的方式
|
||
|
||
```python
|
||
class Aniaml(object):
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
|
||
class Person(Aniaml):
|
||
pass
|
||
|
||
class Cat(Aniaml):
|
||
pass
|
||
|
||
class Dog(Aniaml):
|
||
pass
|
||
```
|
||
|
||
继承的优点也是显而易见的:
|
||
|
||
1. 增加了类的耦合性(耦合性不宜多,宜精)。
|
||
|
||
2. 减少了重复代码。
|
||
|
||
3. 使得代码更加规范化,合理化。
|
||
|
||
## 继承的分类
|
||
|
||
上面的那个例子:
|
||
|
||
- Aminal 叫做父类, 基类, 超类。
|
||
- Person Cat Dog: 子类,派生类。
|
||
|
||
继承:可以分**单继承,多继承**。
|
||
|
||
这里需要补充一下python中类的种类(继承需要):
|
||
|
||
在python2x版本中存在两种类.:
|
||
|
||
- ⼀个叫**经典类**. 在python2.2之前. **不显式继承 `object`类**,是 Python2 的默认类定义方式。
|
||
- ⼀个叫**新式类**. 在python2.2之后出现了新式类, **显式继承 `object`类**(如 `class MyClass(object)`),是 Python2 引入的改进类模型。
|
||
python3x版本中只有一种类:
|
||
python3中使⽤的都是**新式类**. 如果基类谁都不继承. 那这个类会默认继承 object
|
||
|
||
## 单继承
|
||
|
||
### 类名,对象执行父类方法
|
||
|
||
```python
|
||
class Aniaml(object):
|
||
type_name = '动物类'
|
||
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
|
||
def eat(self):
|
||
print('吃',self)
|
||
|
||
class Person(Aniaml):
|
||
pass
|
||
|
||
class Cat(Aniaml):
|
||
pass
|
||
|
||
class Dog(Aniaml):
|
||
pass
|
||
|
||
print(Person.type_name)
|
||
Person.eat('东西')
|
||
print(Person.type_name)
|
||
|
||
p1 = Person('张三','男',18)
|
||
print(p1.__dict__)
|
||
print(p1.type_name)
|
||
p1.type_name = '666'
|
||
print(p1)
|
||
p1.eat()
|
||
```
|
||
|
||
### 执行顺序
|
||
|
||
```python
|
||
class Aniaml(object):
|
||
type_name = '动物类'
|
||
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
|
||
def eat(self):
|
||
print('吃',self)
|
||
|
||
class Person(Aniaml):
|
||
|
||
def eat(self):
|
||
print('%s 用筷子吃饭'%self.name)
|
||
|
||
class Cat(Aniaml):
|
||
pass
|
||
|
||
class Dog(Aniaml):
|
||
pass
|
||
|
||
p1 = Person('张三','男',18)
|
||
p1.eat()
|
||
```
|
||
|
||
### 同时执行类以及父类方法
|
||
|
||
方法一:如果想执行父类的func方法,这个方法并且子类中调用,那么就在子类的方法中写上:父类.func(对象,其他参数)
|
||
|
||
```python
|
||
class Aniaml(object):
|
||
type_name = '动物类'
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
|
||
def eat(self):
|
||
print('吃东西')
|
||
|
||
class Person(Aniaml):
|
||
def __init__(self,name,sex,age,mind):
|
||
Aniaml.__init__(self,name,sex,age)
|
||
self.mind = mind
|
||
|
||
def eat(self):
|
||
Aniaml.eat(111)
|
||
print('%s 吃饭'%self.name)
|
||
class Cat(Aniaml):
|
||
pass
|
||
|
||
class Dog(Aniaml):
|
||
pass
|
||
|
||
p1 = Person('张三','男',18,'想吃东西')
|
||
p1.eat()
|
||
```
|
||
|
||
方法二:利用super,super().func(参数)
|
||
|
||
```python
|
||
class Aniaml(object):
|
||
type_name = '动物类'
|
||
def __init__(self,name,sex,age):
|
||
self.name = name
|
||
self.age = age
|
||
self.sex = sex
|
||
|
||
def eat(self):
|
||
print('吃东西')
|
||
|
||
class Person(Aniaml):
|
||
def __init__(self,name,sex,age,mind):
|
||
# super(Person,self).__init__(name,sex,age)
|
||
super().__init__(name,sex,age)
|
||
self.mind = mind
|
||
|
||
def eat(self):
|
||
super().eat()
|
||
print('%s 吃饭'%self.name)
|
||
class Cat(Aniaml):
|
||
pass
|
||
|
||
class Dog(Aniaml):
|
||
pass
|
||
|
||
p1 = Person('张三','男',18,'想吃东西')
|
||
p1.eat()
|
||
```
|
||
|
||
单继承练习题
|
||
|
||
```python
|
||
class Base:
|
||
def __init__(self,num):
|
||
self.num = num
|
||
def func1(self):
|
||
print(self.num)
|
||
|
||
class Foo(Base):
|
||
pass
|
||
|
||
obj = Foo(123)
|
||
obj.func1()
|
||
# 运⾏的是Base中的func1
|
||
```
|
||
|
||
```python
|
||
class Base:
|
||
def __init__(self,num):
|
||
self.num = num
|
||
def func1(self):
|
||
print(self.num)
|
||
|
||
class Foo(Base):
|
||
def func1(self):
|
||
print("Foo.func1",self.num)
|
||
|
||
obj = Foo(123)
|
||
obj.func1()
|
||
# 运⾏的是Foo中的func1
|
||
```
|
||
|
||
```python
|
||
class Base:
|
||
def __init__(self, num):
|
||
self.num = num
|
||
def func1(self):
|
||
print(self.num)
|
||
self.func2()
|
||
def func2(self):
|
||
print("Base.func2")
|
||
class Foo(Base):
|
||
def func2(self):
|
||
print("Foo.func2")
|
||
|
||
obj = Foo(123)
|
||
obj.func1()
|
||
# func1是Base中的 func2是⼦类中的
|
||
```
|
||
|
||
```python
|
||
class Base:
|
||
def __init__(self, num):
|
||
self.num = num
|
||
def func1(self):
|
||
print(self.num)
|
||
self.func2()
|
||
def func2(self):
|
||
print(111, self.num)
|
||
class Foo(Base):
|
||
def func2(self):
|
||
print(222, self.num)
|
||
|
||
lst = [Base(1), Base(2), Foo(3)]
|
||
for obj in lst:
|
||
obj.func2()
|
||
```
|
||
|
||
```python
|
||
class Base:
|
||
def __init__(self, num):
|
||
self.num = num
|
||
def func1(self):
|
||
print(self.num)
|
||
self.func2()
|
||
def func2(self):
|
||
print(111, self.num)
|
||
class Foo(Base):
|
||
def func2(self):
|
||
print(222, self.num)
|
||
|
||
lst = [Base(1), Base(2), Foo(3)]
|
||
for obj in lst:
|
||
obj.func1()
|
||
```
|
||
|
||
## 多继承
|
||
|
||
```python
|
||
class ShenXian: # 神仙
|
||
def fei(self):
|
||
print("神仙都会⻜")
|
||
class Monkey: # 猴
|
||
def chitao(self):
|
||
print("猴⼦喜欢吃桃⼦")
|
||
class SunWukong(ShenXian, Monkey): # 孙悟空是神仙, 同时也是⼀只猴
|
||
pass
|
||
|
||
sxz = SunWukong() # 孙悟空
|
||
sxz.chitao() # 会吃桃⼦
|
||
sxz.fei() # 会⻜
|
||
```
|
||
|
||
### 经典类的多继承
|
||
|
||
```python
|
||
class A:
|
||
pass
|
||
class B(A):
|
||
pass
|
||
class C(A):
|
||
pass
|
||
class D(B, C):
|
||
pass
|
||
class E:
|
||
pass
|
||
class F(D, E):
|
||
pass
|
||
class G(F, D):
|
||
pass
|
||
class H:
|
||
pass
|
||
class Foo(H, G):
|
||
pass
|
||
```
|
||
|
||
画图
|
||
|
||

|
||
|
||
在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个.
|
||
|
||
类的MRO(method resolution order): Foo-> H -> G -> F -> E -> D -> B -> A -> C.
|
||
|
||
### 新式类的多继承
|
||
|
||
#### mro序列
|
||
|
||
MRO是一个有序列表L,在类被创建时就计算出来。
|
||
|
||
通用计算公式为:
|
||
|
||
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)
|
||
|
||
如果继承至一个基类:class B(A)
|
||
这时B的mro序列为
|
||
|
||
mro( B ) = mro( B(A) )
|
||
= [B] + merge( mro(A) + [A] )
|
||
= [B] + merge( [A] + [A] )
|
||
= [B,A]
|
||
|
||
如果继承至多个基类:class B(A1, A2, A3 …)
|
||
这时B的mro序列
|
||
|
||
mro(B) = mro( B(A1, A2, A3 …) )
|
||
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
|
||
= ...
|
||
|
||
计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
|
||
|
||
#### 表头和表尾
|
||
|
||
表头:列表的第一个元素
|
||
|
||
表尾:列表中表头以外的元素集合(可以为空)
|
||
|
||
示例:列表:[A, B, C] 表头是A,表尾是B和C
|
||
|
||
#### 列表之间的+操作
|
||
|
||
[A] + [B] = [A, B]
|
||
|
||
merge操作示例:
|
||
|
||
如计算merge( [E,O], [C,E,F,O], [C] )
|
||
有三个列表 : ① ② ③
|
||
|
||
1 merge不为空,取出第一个列表列表①的表头E,进行判断
|
||
各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
|
||
2 取出列表②的表头C,进行判断
|
||
C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
|
||
merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
|
||
3 进行下一次新的merge操作 ......
|
||
---------------------
|
||
|
||

|
||
|
||
计算mro(A)方式:
|
||
|
||
mro(A) = mro( A(B,C) )
|
||
|
||
原式= [A] + merge( mro(B),mro(C),[B,C] )
|
||
|
||
mro(B) = mro( B(D,E) )
|
||
= [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
|
||
= [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
|
||
= [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
|
||
= [B,D,E] + merge([O] , [O])
|
||
= [B,D,E,O]
|
||
|
||
mro(C) = mro( C(E,F) )
|
||
= [C] + merge( mro(E), mro(F), [E,F] )
|
||
= [C] + merge( [E,O] , [F,O] , [E,F] )
|
||
= [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
|
||
= [C,E,F] + merge([O] , [O])
|
||
= [C,E,F,O]
|
||
|
||
原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
|
||
= [A,B] + merge( [D,E,O], [C,E,F,O], [C])
|
||
= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
|
||
= [A,B,D,C] + merge([E,O], [E,F,O])
|
||
= [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
|
||
= [A,B,D,C,E,F] + merge([O], [O])
|
||
= [A,B,D,C,E,F,O]
|
||
|
||
那既然python提供了. 为什么我们还要如此⿇烦的计算MRO呢? 因为笔试.......你在笔试的时候, 是没有电脑的. 所以这个算法要知道. 并且简单的计算要会. 正式项⽬开发的时候很少有⼈这么去写代码. |