博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象之继承、封装与多态
阅读量:7294 次
发布时间:2019-06-30

本文共 7805 字,大约阅读时间需要 26 分钟。

继承

继承是面向对象中的一个重要概念,通过如果要创建的类与以有的类大部分属性、方法类似,那么可以通过继承的方式创建。一个类可以继承一个或多个类,继承一个类称为单继承,继承多个类称为多继承。被继承的类称为父类,也称为超类或基类,继承的类称为子类或派生类。

继承的实现

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):    passclass Dog(Animal):    passclass Husky(Dog, Animal):   # 多继承    pass

 

查看继承

# __base__查看从左到右继承的第一个类;__bases__是查看继承的所有父类print(Cat.__base__)     # 
print(Husky.__base__) #
print(Husky.__bases__) # (
,
)

在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 eating40 c1.climb()   # 调用Cat类的方法    climb a tree41 42 d1.eat()    # 先从Dog类里面寻找,找到了就不去animal类里找   eat bones43 d1.play()   # 调用Animal类的方法  sara is playing44 45 h1.eat()    # 调用Dog类中的eat方法  eat bones46 h1.guard()  # 调用Dog类中的guard方法  guard the door47 h1.play()   # 调用Animal类的play方法   kevin is playing48 h1.bite_shoes()   # 调用Husky类的方法   bite shoes

 

 多继承的查找顺序

经典类:深度优先

class A:       passclass B(A):    passclass C(A):    passclass D(C, A):    passclass E(D, B):    passclass 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):    passclass D(O):    passclass E(O):    passclass F(O):    passclass B(D, E):    passclass C(E, F):    passclass 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__)   # (
,
,
,
,
,
,
,
)

 

下面再来练习以下,写出如下的MRO列表

class O(object):    passclass H(O):    passclass I(object):    passclass M(object):    passclass D(O, M):    passclass N(M):    passclass E(H, I):    passclass B(D, E):    passclass G(object):    passclass F(G):    passclass C(E, F):    passclass 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__)  # (
,
,
,
,
,
,
,
,
,
,
,
,
)

可以发现,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:    passclass 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.shows2_obj = S2()Func(s2_obj)  # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.showPython伪代码实现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 等等 这就是互称为鸭子类型。鸭子类型

 

转载于:https://www.cnblogs.com/zzliu/p/10273003.html

你可能感兴趣的文章