一.继承
什么是继承
继承是指一种创建新类的方法,在python中我们可以将一新建的类继承一个父类或者多个父类,新建的类称为子类或者派生类,他继承的父类称之为基类和超类
通过类的__bases__属性,我们可以查看一个类继承的父类
class Animal:
pass
class People(Animal):
pass
print(People.__bases__) #(<class '__main__.Animal'>,)
在python2中有经典类和新式类之分,经典类是指没有继承object类的类,新式类则相反,在python3中所有的类都被统一成了新式类,新式类中有一些常用的功能能够被派生类使用。
继承与抽象
继承是对象功能的提取,那么父类则需要总结子类共有的功能属性,抽象提取。
属性查找
有类继承关系,对象会先从自己中找,如果没有再去类,然后再去父类中查找
class Animal:
a = 1
class People(Animal):
pass
people = People()
print(people.a)
继承的实现原理
菱形问题
在python中独有的多继承模式会造成菱形问题,菱形问题是指子类的多个父类指向同一个子类
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B,C):
pass
继承原理
那么这样的继承必然会导致个问题,假设在B和C中都对A的一个功能进行了重写,那么在查找的过程中会查找B还是C的?
python如何实现属性查找
在python类中有一个mro列表,遵循了C3算法提供了继承了路径问题
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B,C):
pass
print(D.mro())
#[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
python会根据列表的索引从列表的左侧到右侧依次查询,如果在左侧查询到则停止查询。
MRO三条准则:
1.子类会优先于父类被查找
2.如果有多个父类,则会依据顺序查找
3.如果有多个选择,则优先查找索引在前的
如果是对象发起则会先从自己找,然后遵循mro
如果是类发起则会遵循mro
4.3 深度优先和广度优先原则
非菱形继承
会遵循深度优先原则, 一条路走到黑然后再走宁外一条道路
class E:
pass
class B(E):
pass
class F:
pass
class C(F):
pass
class D:
pass
class A(B,C,D):
pass
print(A.mro())
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
菱形问题
经典类的查找顺序
经典类会依据深度优先原则
经典类会一条路走到黑,依据一条路查询结束后才会查询第二条路
class G: # 在python2中,未继承object的类及其子类,都是经典类
def test(self):
print('from G')
class E(G):
def test(self):
print('from E')
class F(G):
def test(self):
print('from F')
class B(E):
def test(self):
print('from B')
class C(F):
def test(self):
print('from C')
class D(G):
def test(self):
print('from D')
class A(B,C,D):
# def test(self):
# print('from A')
pass
obj = A()
obj.test() # 如上图,查找顺序为:obj->A->B->E->G->C->F->D->object
# 可依次注释上述类中的方法test来进行验证
新式类会根据广度优先原则
对于直接继承object的类会放在最后查找
class G:
pass
class E(G):
pass
class B(E):
pass
class F(G):
pass
class C(F):
pass
class D(G):
pass
class A(B,C,D):
pass
print(A.mro())
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
python的Mixins机制
一个子类继承了多个父类这通常不符合人们的逻辑观念,一个子类应当只有一个亲生父亲,因此python中推出了Mixins机制,这只是一种代码的行为规范,是指在类名后加上Mixins,able,ible等,表示这个类只是为类来混合一个功能,可以理解为后爸同时在养他,这样就遵循了人们常规的逻辑观念
class People:
print('name')
class FatherMixin:
@staticmethod
def say():
print('hello!')
class Monk(FatherMixin, People):
def __init__(self, sb):
self.name = sb
monk = Monk('sb')
monk.say()
派生与方法重启
子类可以根据父类已经拥有的类派生出新的类,但是如果在重写中仍然需要用到子类的功能的话,我们则可以调用父类中的方法然后再添加新的代码来改写。
调用父类方法之直接使用
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(People):
def __init__(self, name, age, gender, class_):
People.__init__(self, name, age, gender) # 调用类中的方法需要手动传入所有参数
self.class_ = class_
p = Student('WW',18,'男','清华一班')
print(p.__dict__)
重写父类方法之super方法
调用super会遵循mro的原则查找父类中的方法
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(People):
def __init__(self, name, age, gender, class_):
super().__init__(name, age, gender) # 使用super方法会自动将此类的实例化对象传入父类的__init__方法
self.class_ = class_
p = Student('WW',18,'男','清华一班')
print(p.__dict__)
组合
组合指在一个类中以另外一个类的对象作为对象,传入这个类中,这样我们就可以高度整合两个类,则我们可以将一个人所具备的各分为几个部分来组合
class Information:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def tell_information(self):
print('name:%s age:%s gender%s'%(self.name,self.age,self.gender))
class Course:
def __init__(self,name,price,data,teacher):
self.name = name
self.price = price
self.data = data
self.teacher = teacher
def tell_course(self):
print('name:%s age:%s data:%s gender:%s' % (self.name,self.price,self.data,self.teacher))
class Student:
def __init__(self,course,information):
self.course = course
self.information = information
def say(self):
print('%s' % self.course)
information = Information('ww',18,'男')
course = Course('python','12000','12.10','ww')
student = Student(course,information)
student.course.tell_course()
# name:python age:12000 data:12.10 gender:ww