面向对象之继承、封装与多态
面向对象之继承、封装与多态
继承
继承是面向对象中的一个重要概念,通过如果要创建的类与以有的类大部分属性、方法类似,那么可以通过继承的方式创建。一个类可以继承一个或多个类,继承一个类称为单继承,继承多个类称为多继承。被继承的类称为父类,也称为超类或基类,继承的类称为子类或派生类。
继承的实现
class Animal:
def __init__(self, name, age, color):
self.name = name
self.age = age
self.color = color
def eat(self):
print("%s is eating" % self.name)
def play(self):
print("%s is playing" % self.name)
class Cat(Animal):
pass
class Dog(Animal):
pass
class Husky(Dog, Animal): # 多继承
pass
查看继承
# __base__查看从左到右继承的第一个类;__bases__是查看继承的所有父类 print(Cat.__base__) # <class '__main__.Animal'> print(Husky.__base__) # <class '__main__.Dog'> print(Husky.__bases__) # (<class '__main__.Dog'>, <class '__main__.Animal'>)
在python3 中,如果怕不指定基类,则会默认继承object类,object类是所有python类的基类。继承object类的类称为新式类,否则称为经典类,python3中的类都是新式类,Python2既有新式类,又有经典类。


继承的好处
继承的一个很重要的好处就是能够减少重复的代码
1 class Animal:
2 def __init__(self, name, age, color):
3 self.name = name
4 self.age = age
5 self.color = color
6
7 def eat(self):
8 print("%s is eating" % self.name)
9
10 def play(self):
11 print("%s is playing" % self.name)
12
13
14 class Cat(Animal): # 继承Animal类
15 def climb(self):
16 print("climb a tree")
17
18 def catch_mouses(self):
19 print("catch a mouse")
20
21
22 class Dog(Animal):
23 def eat(self):
24 print("eat bones")
25
26 def guard(self):
27 print("guard the door")
28
29
30 class Husky(Dog, Animal): # 多继承,同时继承Dog类和Animal类
31 def bite_shoes(self):
32 print("bite shoes")
33
34
35 c1 = Cat("pikaqiu", 1, "orange")
36 d1 = Dog("sara", 2, "white")
37 h1 = Husky("kevin", 1, "grey")
38
39 c1.eat() # 调用Animal中的方法 pikaqiu is eating
40 c1.climb() # 调用Cat类的方法 climb a tree
41
42 d1.eat() # 先从Dog类里面寻找,找到了就不去animal类里找 eat bones
43 d1.play() # 调用Animal类的方法 sara is playing
44
45 h1.eat() # 调用Dog类中的eat方法 eat bones
46 h1.guard() # 调用Dog类中的guard方法 guard the door
47 h1.play() # 调用Animal类的play方法 kevin is playing
48 h1.bite_shoes() # 调用Husky类的方法 bite shoes
多继承的查找顺序
经典类:深度优先
class A:
pass
class B(A):
pass
class C(A):
pass
class D(C, A):
pass
class E(D, B):
pass
class F(E, D):
pass
将上述的继承顺序以图的形式画出来,红色为继承顺序,绿色为查找顺序

查找顺序为: F-->E-->D-->C-->A
新式类:C3算法
(1) 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算法的核心。
(2) 表头与表尾
表头:列表的第一个元素
表尾:列表中除表头以外的元素的集合(可以为空)
示例:列表 [A, B, C]
表头是A,表尾是B和C
(3) +操作
[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外,并将所有表头的C删除 merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) 3 进行下一次新的merge操作 ...... ---------------------
示例,有如下继承关系,要计算其MRO顺序
class O(object):
pass
class D(O):
pass
class E(O):
pass
class F(O):
pass
class B(D, E):
pass
class C(E, F):
pass
class A(B, C):
pass
首先画出其继承关系图

然后计算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里面可以用A.__mro__的方法查看mro列表
print(A.__mro__) # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class '__main__.O'>, <class 'object'>)
下面再来练习以下,写出如下的MRO列表
class O(object):
pass
class H(O):
pass
class I(object):
pass
class M(object):
pass
class D(O, M):
pass
class N(M):
pass
class E(H, I):
pass
class B(D, E):
pass
class G(object):
pass
class F(G):
pass
class C(E, F):
pass
class A(B, C):
pass
首先画出继承关系图

按照上面的merge操作计算:
mro(A)=mro(A(B,C))
= [A] + merge(mro(B),mro(C),[B,C])
先算mro(B)
mro(B) = mro(B(D,E))
= [B] + merge(mro(D),mro(E),[D,E])
= [B] + merge([D,M,N,O],[E,H,O,I],[D,E])
= [B] + [D] + merge([M,N,O],[E,H,O,I],[E])
= [B,D] + [M] + merge([N,O],[E,H,O,I],[E])
= [B,D,M] + [N] + merge([O],[E,H,O,I],[E])
= [B,D,M,N] + [E] + merge([O],[H,O,I])
= [B,D,M,N,E] + [H] + [O,I]
= [B,D,M,N,E,H,O,I]
再算mro(C)
mro(C) = mro(C(E,F))
= [C] + merge(mro(E),mro(F),[E,F])
= [C] + merge([E,H,O,I],[F,G],[E,F])
= [C] + [E] + merge([H,O,I],[F,G],[F])
= [C,E] + [H] + merge([O,I],[F,G],[F])
= [C,E,H,O,I] + merge([F,G],[F])
= [C,E,H,O,I,F,G]
将mro(B)和mro(C)代入mro(A)里面
mro(A) = [A] + merge([B,D,M,N,E,H,O,I],[C,E,H,O,I,F,G],[B,C])
= [A] + [B] + merge([D,M,N,E,H,O,I],[C,E,H,O,I,F,G],[C])
= [A,B] + [D] + merge([M,N,E,H,O,I],[C,E,H,O,I,F,G],[C])
= [A,B,D,M,N] + merge([E,H,O,I],[C,E,H,O,I,F,G],[C])
= [A,B,D,M,N,C] + merge([E,H,O,I],[E,H,O,I,F,G])
= [A,B,D,M,N,C,E,H,O,I,F,G]
最终的mro(A)=[A,B,D,M,N,C,E,H,O,I,F,G]
验证结果
print(A.__mro__) # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.M'>, <class '__main__.N'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.H'>, <class '__main__.O'>, <class '__main__.I'>, <class '__main__.F'>, <class '__main__.G'>, <class 'object'>)
可以发现,C3是把我们多个类产⽣的共同继承留到最后去找 ,如果没有所谓的共同继承关系. ⼏乎就可以当成是深度遍历。
封装
封装,顾名思义是将内容封装到某个地方,然后再去调用被封装到某处的内容。所以运用面向对象的封装特性时,需要注意两点:
将内容封装到某处
从某处调用被封装的内容
1. 将内容封装到某处
class Person:
def __init__(self, name, age):
self.name = name # 这里就是封装!
self.age = age # 把name,age这两个变量封装到对象的name和age这个属性里
2. 从某处调用被封装的内容
调用被封装的内容有两种方式:直接调用和间接调用
class Person:
def __init__(self, name, age):
self.name = name # 这里就是封装!
self.age = age # 把name,age这两个变量封装到对象的name和age这个属性里
def get_name(self):
print(self.name) # 间接调用
p1 = Person("章北海", 25)
print(p1.name) # 直接调用
p1.get_name() # 间接调用
小结:面向对象中封装就是将内容(属性或方法)封装到对象中,然后通过对象直接或间接获取到被封装的内容
多态
多态,就是一个对象多种状态,python是默认支持多态的
# 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。
def func(int a):
print('a必须是数字')
# 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
def func(a):
print('a是什么都可以')
# 再比如:
class F1:
pass
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象
def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""
print obj.show()
s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show
s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
Python伪代码实现Java或C # 的多态
多态举例
python通过鸭子模型实现多态
python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
对于代码上的解释其实很简答:
class A:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
class B:
def f1(self):
print('in A f1')
def f2(self):
print('in A f2')
obj = A()
obj.f1()
obj.f2()
obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互称为鸭子类型。
# 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。
鸭子类型

浙公网安备 33010602011771号