继承派生新式类与经典类

Posted ghylpb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了继承派生新式类与经典类相关的知识,希望对你有一定的参考价值。

继承

Downwards is the only way forwards .——《盗梦空间》

面向对象阶段最重要的知识点:继承、封装、多态

1.什么是继承?

指新建类的方法,新建的类称之为子类或者派生类,子类继承的类叫做父类,也称之为基类或者超类。
继承特征:
子类可以继承父类的属性(特征与技能),并且可以派生出自己的属性(特征与技能)。
在python中一个子类可以继承多个父类,其他语言一个子类只可以继承一个父类

2.为什么要继承?

继承的目的是为了减少代码的冗余(减少重复代码)

3.如何实现继承?

1.首先要确定好谁是子类谁是父类.
2.在定义类时子类+(),()内写父类,实现继承.

class 父类:
     pass

class 子类(父类):
     pass
#父类
class ParentClass1:
    pass

class ParentClass2:
    pass
#子类
class Subclass1(ParentClass1):
    pass

class Subclass2(ParentClass1,ParentClass2):
    pass

print(Subclass2.__bases__)
#(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
#查看继承的父类:__bases__,是类的属性,用来查找自己的父类,通过元组的形式返回所继承的父类

寻找继承关系

如何寻找继承关系?
要想寻找继承关系,首先抽象再继承。
——先抽象(抽象思想):
技术图片

奥巴马——》人类——》动物类
麦兜——》猪类——》动物类
小丁丁——》狗类——》动物类
抽象定义动物类,父类。
特征:眼睛、鼻子...
技能:
吃喝...

——再继承(在程序中)
技术图片

继承的关系:
对象:特征与技能的结合体
类:一系列特征与技能的结合体
继承:一系列类相同的特征与技能的结合体

class SchoolPeople:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

class Students(SchoolPeople):
    def choose_course(self):
        print(f'{self.name} is choosing course.')

class Teachers(SchoolPeople):
    def teach(self):
        print(f'{self.name} is teaching students.')

stu1 = Students('xiaoming','15','男')
stu1.choose_course()

xiaoming is choosing course.

继承背景下对象属性的查找顺序

对象查找属性先从自己的名称空间查找,若当前类是子类,并且没有该属性,就去父类中查找,如果父类也没有就报错__class__查看当前对象的类。
注意:对象查找属性不管父类有没有这个属性,只要子类有就不会去父类中查找

查看对象名称空间
print(tea1.__dict__)
查看对象的属性,查看当前对象的类__class__

查看子类名称空间
print(tea1.__class__.__dict__)
查看父类名称空间
print(tea1.__class__.__bases__[0].__dict__)#查看第一个父类的名称空间

#验证对象属性的查找顺序
class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.f1()

class Soo(Foo):
    def f1(self):
        print('Soo.f1')

soo_obj = Soo()
soo_obj.f2()
'''
Foo.f2
Soo.f1
'''

派生

什么是派生?

派生指子类继承父类的属性,并且派生自己的属性。
如果子类和父类都有这个属性,以子类自己的属性为准。
继承指的是类与类的关系,子类与父类是从属关系。

子类派生出新的属性,并重用父类的属性

class SchoolPeople:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

class Teacher(SchoolPeople):
    def __init__(self,name,age,gender,level,sal):
        SchoolPeople.__init__(self,name,age,gender)#重用父类的属性
        self.level = level#派生出的属性
        self.sal = sal#派生出的属性

tech1 = Teacher('xiaohua','17','男','10','5w')
print(tech1.level)

重用父类属性的两种方式

方式一:

直接通过父类.(调用)__init__,把__init__当做普通函数使用,传入对象与继承的属性,如上例中的重用。
方式二:

super是一个特殊的类,在子类中调用super()会得到一个特殊的对象,通过“.”
指向父类的名称空间。

class SchoolPeople:
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

class Teacher(SchoolPeople):
    def __init__(self,name,age,gender,level,sal):
        super().__init__(name,age,gender)#重用父类的属性(注意括号里面没有self)
        self.level = level#派生出的属性
        self.sal = sal#派生出的属性

注意:两种方式不要混着使用

新式类与经典类

新式类与经典类(了解)(面试会问)

在python2中才有经典类,没有继承object的类都是经典类。

python3中都是新式类,继承object类的都是新式类,py3中默认继承object类。

钻石继承(菱形继承)

关于mro()

mro():是object——》type的函数,用来查看多继承情况下,当前类的继承顺序, .mro()方法其实就是在查找mro()方法
一个子类如果继承多个父类,属性的查找顺序是从左向右依次查找,最后找object

钻石继承

钻石继承(菱形继承):钻石继承就是一个子类有多个父类,每个父类又有多个不同的父类......这些父类的祖先最终是同一个祖宗。(面试问)

在多继承情况下可能会出现钻石继承的情况。

钻石继承下对象属性的查找顺序

--经典类——》深度优先:从左向右查找,一条分支找到底,若果没找到就去另一条分支继续找。

技术图片

——新式类——》广度优先:从左向右查找,和经典类的区别是最后找所有分支共同的父类

技术图片

验证查找顺序代码

class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B):
    def test(self):
        print('from D')

class E(C):
    def test(self):
        print('from E')

class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类

通过继承实现修改json模块数据类型

通过继承实现为json增加数据类型:

import json
from datetime import date ,datetime
print(json.JSONDecoder)#<class 'json.decoder.JSONDecoder'>
print(datetime.today())#当前时间
print(date.today())#当前日期
#从开发者的角度考虑,可以将json不支持的数据类型转成json支持的是数据类型
#如:
'''dict1 = {
    'name':'tank',
    'today':str(datetime.today()),
    'today1':str(date.today())
}
res = json.dumps(dict1)
print(res)
#{"name": "tank", "today": "2019-10-10 14:30:26.967368", "today1": "2019-10-10"}
从开源者的角度考虑,Python time strftime() 函数接收以时间元组,并返回以可读字符串表示的当地时间,
        格式由参数format决定。'''
class MyJson(json.JSONEncoder):
    def default(self,o):
        if isinstance(o,datetime):#判断o是否是datetime的一个实例对象
            return o.strftime('%Y-%m-%d %X')

        elif isinstance(o,date):
            return o.strftime('%Y-%m-%d')
        else:
            return super().default(self,o)#在json中也有default这个方法

dict1 = {
    'name':'tank',
    'today':datetime.today(),
    'today1':date.today()
}
res = json.dumps(dict1,cls = MyJson)#cls=None,默认指向的是原json的JSONEncoder,加上之后优先使用外面的类
print(res)

以上是关于继承派生新式类与经典类的主要内容,如果未能解决你的问题,请参考以下文章

面向对象进阶

python2中的新式类与经典类区别

python2中的新式类与经典类区别

新式类与经典类的比较

继承与派生

经典类与新式类的继承顺序