面向对象-继承

面向对象的三大特征
面向对象的三大特征:封装,继承,多态。
继承
继承就是新建类的一种的方式,新建的类我们称为子类或者叫派生类,被继承的类外卖叫父类或者基类。子类可以使用父类中的属性或者方法。
为什么要用继承:
类解决了对象与对象之间的代码冗余问题,继承解决了类与类之间的代码冗余问题。
如何使用:
在继承方面python2和python3是有区别的,python2分新式类和经典类,区分标准在于是否继承object类。在python3中自动默认继承了object。
子类调用父类
子类继承了父类,子类自动拥有了父类所有的属性,那么子类如果调用父类的方法呢?

图中1:指名道姓地调用,那么这种调用和继承其实没有多大关系,就算没有继承也是可以实现的。
图中2:用super()关键字,在python2中,括号内需要写上类名+self,但是python3中可以省略掉。
继承下的属性查找
单继承:自下而上找,现在对象本身的名称空间找,再从子类中找,找不到再往上到父类中查找。一直到找到为止,找不到报错。
多继承:新式类广度优先,经典类深度优先。
新式类:
class A(object):
def test(self):
print('from A')
class B(A):
pass
class C(A):
pass
class D(B):
pass
class E(C):
pass
class F(D, E):
pass
f1 = F()
f1.test()
查找顺序为 F->D->B->E->C->A
经典类:
class A():
def test(self):
print('from A')
class B(A):
pass
class C(A):
pass
class D(B):
pass
class E(C):
pass
class F(D, E):
pass
f1 = F()
f1.test()
查找顺序为 F->D->B->A->E->C
super列表和mro列表
super列表
在类的继承中同事可以,如果重新定义某个当法,该方法会覆盖父类的同名方法,但是有时,我们希望同时实现父类的功能,这时我我们就需要调用父类的方法了,这时可以通过super()来实现。

但是,super方法实际上和父类没有关联,它是遵循mro列表工作的。
mro列表

mro列表是通过C3线性化算法来实现的,就是一个mro列表合并所有父类的列表,并且遵循以下几点:
(1)子类永远在父类的前面
(2)如果有多个父类,会根据它们在列表中的顺序去检查
(3)如果下一个类中有两种不同的合法选择,那么选择第一个父类。
多态与鸭子类型
python是一门动态语言,它并不要求严格的继承体系,一个对象只要看起来像鸭子,走起里来像鸭子,那它就可以被看作是鸭子。
class Animal:
def speak(self):
pass
class People(Animal):
def speak(self):
print('哈哈')
class Dog(Animal):
def speak(self):
print('汪汪')
class Pig(Animal):
def speak(self):
print('哼哼')
def speak(animal):
animal.speak()
obj = Pig()
obj1 = People()
obj2 = Dog()
speak(obj)
上面Animal是一个类,动物拥有speak的功能,所以以下只要拥有speak功能我们都认为是动物,这也是鸭子类型。
但是这种方法不是强制性的,如果需要强制性,子类必须拥有和父类一样的功能。
方法一:
class Animal(metaclass=abc.ABCMeta):
@abc.abstracmethond
def speak(self):
pass
class People(Animal):
def speak(self):
print('哈哈')
以上方法class Animal就是抽象类了,抽象类只能被继承,不能被实例化,如果子类里面没有speak功能那么会报错。
方法二:
class Animal:
def speak(self):
raise Exception:
print('请务必实现speak功能')
pass
class People(Animal):
def speak(self):
print('哈哈')
以上方法为主动抛异常,如果子类里面没有speak功能那么会抛出异常。
浙公网安备 33010602011771号