面向对象之:继承(inheritance)
1.什么是面向对象的继承
继承是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。
简单的说,都通过子承父业,合法继承资产,如果你是独生子,那么不出意外你会继承你父母的全部财产。
简单的继承例子:
class Animal: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Dog: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex #继承 class Animal: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Dog(Animal): pass
2.继承的特点
-
增加了类与类的耦合性
-
减少重复代码
3.继承的分类
在上面的例子中
Animal称父类,基类,超类
Dog称子类,派生类
继承
-
单继承
-
多继承
4.单继承
简单用法
class Animal: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Dog(Animal): def run(self): print(f"{self.name}正在跑。。。") dog1=Dog('大黄',8,'母') dog1.run()
这个例子中,dog属于动物类,而动物类有共同的属性name,age,sex,如果我们每个动物类都初始化name,age,sex代码冗余,效率低。
同时执行类以及父类的方法
class Animal: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Dog(Animal): def __init__(self,name,age,sex,speed): super().__init__(name,age,sex) self.speed=speed def run(self): print(f"{self.name}正在以{self.speed}迈的速度跑。。。") dog1=Dog('大黄',8,'母',35) dog1.run()
5.多继承
话不多说上代码,自己体会一下
class Fairy:#神仙类 def fly(self): print('神仙会飞。。。') class Monkey: #猴子类 def eat(self): print("猴子偷桃吃!!!") class SunMonkey(Fairy,Monkey): pass sun1=SunMonkey() sun1.fly() sun1.eat()
看过西游记的都知道,孙悟空既是猴子又是神仙,在上面代码中,他自然就继承了两个类中的方法这就是简单的多继承。
那既然继承两个类,那就要涉及到继承顺序的问题。
新式类的多继承
这里需要补充一下python中类的种类:
在python2x版本中存在两种类.:
-
⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
-
⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
-
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object
mro序列-C3算法
mro是一个有序列表,在类被创建是就计算出来了
通用公式
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] ) (其中Child继承自Base1, Base2)
其中merge操作是c3算法的核心
下面介绍一些关于公式的知识
表头与表尾
-
表头--列表的第一个元素
-
表尾--列表中表头以外元素的集合,(有可能为空)
下面我计算一个来演示一下计算过程
class A(object): pass class B(A): pass class C(A): pass class D(A): pass class E(B,C): pass class F(C,D): pass class G(D): pass class H(E,F): pass class I(F,G): pass
公式: mro(K(H,I))=[K]+merge(mro(H),mro(I),[H,I]) 计算mro(H)--由上面的代码看出H类继承E,F两个类 mro(H(E,F))=[H]+merge(mro(E),mro[F],[E,F]) 再分别计算mro(H)中的mro(E),mro(F) mro(E(B,C))=[E]+merge(mro(B),mro(c),[B,C]) 有代码看出B类由继承A类 =[E]+merge([B,A],[C,A],[B,C]) #就这样依次计算出mro(E),mro(F)进而计算出mro(H),在按照这个思路计算出mro(I).................. 最后得到: mro(K(H,I))=[K]+merge([H,E,B,F,C,D,A],[I,F,C,G,D,A],[H,I]) 再依照merge操作 最后计算出结果如下: [K,H,E,B,I,F,C,G,D,A] 这就是这些继承类的执行顺序
merge操作实例
如计算merge( [E,O], [C,E,F,O], [C] ) 有三个列表 : ① ② ③ merge不为空,取出第一个列表列表①的表头E,进行判断 各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表 取出列表②的表头C,进行判断 C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除 merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] ) 进行下一次新的merge操作 ...... ---------------------
这下就计算OK了。
最后说一下python提供的方法计算执行顺序
print(mro(A))
上面代码的结果如下
[<class '__main__.K'>, <class '__main__.H'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.I'>,
<class '__main__.F'>,
<class '__main__.C'>, <class '__main__.G'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
看到这很多人就会疑惑了,既然有python的方法,哪还手动推导干嘛呢?
那我想问你,当你去笔试的时候,没有电脑你怎么办呢?所以这个简单的算法要会。