python类的三大特性之继承

一.继承

什么是继承

继承是指一种创建新类的方法,在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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值