10.10 继承

继承

1.什么是继承:继承指的是新建类的方法,新建的类称之为子类或者派生类。

子类继承的类叫做父类,也称之为基类或超类

继承的特征:子类可以继承父类的属性(特征与技能),并且可以派生出自己的属性。

注意:在Python中,一个子类可以继承多个父类,其他的语言只能一个子类继承一个父类。

2.为什么要继承?

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

3.如何实现继承?

首先要确定好谁是子类,谁是父类。

在定义类时,子类+(),()内写父类,实现继承。

class 父:
    xxx=100
    pass
class 子(父):
    pass

一、继承初体验

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

#继承多个父类
class SubClass2(ParentClass1,ParentClass2):
    pass

#查找继承的父类:__bases__是类的属性,用来查找当前类的父类:
print(SubClass1.__bases__)
print(SubClass2.__bases__)

运行结果:
(<class '__main__.ParentClass1'>,)
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

二、寻找继承关系

如何寻找继承关系:要想寻找继承关系,首先要‘先抽象,再继承’。

什么是抽象?抽象指的是抽取相似的部分。

继承的关系:

对象是特征与技能的结合体。

类是一系列对象相同的特征与技能的结合体。

继承是一系列类相同的特征与技能的结合体。

#老男孩选课系统

#不继承情况下:
#老师类:名字,年龄,性别
class OldboyTeacher:
    school='oldboy'

    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    #老师修改分数技能:
    def change_score(self):
        print(f'老师[{self.name}]修改分数。。。')

#学生类:名字,年龄,性别
class OldboyStudent:
    school='oldboy'

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    #学生可以选择课程
    def choose_course(self,course):
        print(f'学生[{self.name}]选择课程[{course}]')

stu1=OldboyStudent('王同学',95,'female')
tea1=OldboyTeacher('jsjdn',80,'male')

print(stu1.name,stu1.age,stu1.sex)
print(tea1.name,tea1.age,tea1.sex)
print(stu1.choose_course('python'))
print(tea1.change_score())

运行结果:
王同学 95 female
jsjdn 80 male
学生[王同学]选择课程[python]
None
老师[jsjdn]修改分数。。。
None
'''
抽象:
school
__init__(self,name,age,sex)
'''
class OldboyPeople:
    school='oldboy'

    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

#老师类:名字,年龄,性别
class OldboyTeacher(OldboyPeople):
    #老师修改分数技能
    def change_score(self):
        print(f'老师[{self.name}]修改分数。。')
#学生类:名字,年龄,性别
class OldboyStudent(OldboyPeople):
    #学生可以选课
    def choose_course(self,course):
        print(f'学生[{self.name}选择课程[{course}]')

stu1=OldboyStudent('王同学',95,'female')
tea1=OldboyTeacher('jsjdn',80,'male')

print(stu1.name,stu1.age,stu1.sex)
print(tea1.name,tea1.age,tea1.sex)
print(stu1.choose_course('python'))
print(tea1.change_score())

三、继承背景下,对象属性查找顺序

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

1.对象查找属性会先从对象的名称空间中查找。

2.若对象没有,则会去类里面找。

3.若当前类是子类,并且没有对象找的属性,会去父类中查找。

注意:对象查找属性,若子类有,不管父类有没有,以子类的为准。

#父类
class OldboyPeople:
    school='oldoy'

    def __init__(self,name,age,sex):

        self.name=name
        self.age=age
        self.sex=sex

#子类
#老师类:名字,年龄,性别
class OldboyTeacher(OldboyPeople):
    #老师修改分数技能
    def change_score(self):
        print(f'老师[{self.name}]修改分数。。')

tea1=OldboyTeacher('tank',18,'male')
print(tea1.school)

#查看对象名称空间
print(tea1.__dict__)
#__class__:对象的属性,查看当前对象的类。
#查看子类名称空间
print(tea1.__class__.__dict__)
#查看父类名称空间
print(tea1.__class__.__bases__[0].__dict__)

#验证对象属性的查找顺序1

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()
运行结果:
oldoy
{'name': 'tank', 'age': 18, 'sex': 'male'}
{'__module__': '__main__', 'change_score': <function OldboyTeacher.change_score at 0x00000000021927B8>, '__doc__': None}
{'__module__': '__main__', 'school': 'oldoy', '__init__': <function OldboyPeople.__init__ at 0x0000000002192730>, '__dict__': <attribute '__dict__' of 'OldboyPeople' objects>, '__weakref__': <attribute '__weakref__' of 'OldboyPeople' objects>, '__doc__': None}
Foo.f2
Soo.f1

# 验证对象属性的查找顺序2
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.f1()  # Soo.f1

四、派生:

1.什么是派生?

派生指的是子类继承父类的属性,并且派生出新的属性。

子类派生出新的属性,若与父类的属性相同,则以子类的为准。

继承是谁与谁的关系,指的是类与类的关系,子类与父类是从属关系。

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

class OldboyPeople:
    school='oldoy'

    def __init__(self,name,age,sex):

        self.name=name
        self.age=age
        self.sex=sex


class OldboyTeacher(OldboyPeople):
    school='oldboy'
    #等级、薪资
    def __init__(self,name,age,sex,level,sal):
        self.name=name
        self.age=age
        self.sex=sex
        self.level=level
        self.sal=sal

class OldboyStudent(OldboyPeople):
    school='oldboy'
    #课程
    def __init__(self,name,age,sex,course):
        self.name=name
        self.age=age
        self.sex=sex
        self.course=course

问题:子类继承父类的__init__毫无意义

解决方式有两种:

方式一:直接通过 父类.(调用)__init__,把__init__当作普通函数使用,传入对象与继承的属性。

方式二:super是一个特殊的类,在子类中调用super()会得到一个特殊的对象,通过'.'指向的是父类的名称空间

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

#方式一:
class OldboyPeople:
    school='oldoy'

    def __init__(self,name,age,sex):

        self.name=name
        self.age=age
        self.sex=sex

class OldboyTeacher(OldboyPeople):
    school='oldboy'
    #等级、薪资
    def __init__(self,name,age,sex,level,sal):
        OldboyPeople.__init__(self,name,age,sex)
        self.level=level
        self.sal=sal
class OldboyStudent(OldboyPeople):
    school='oldboy'
    #课程
    def __init__(self,name,age,sex,course):
        OldboyPeople.__init__(self,name,age,sex)
        self.course=course

    def choose_course(self):
        print(f'学生[{self.name}]选择课程[{self.course}]')

stu1=OldboyStudent('王同学',95,'female','python')
tea1=OldboyTeacher('jsjdn',80,'male',9,3.0)

print(stu1.name,stu1.course)
print(tea1.name,tea1.level)
print(stu1.choose_course())

运行结果:
王同学 python
jsjdn 9
学生[王同学]选择课程[python]
None    

#方式二:
class OldboyTeacher(OldboyPeople):
    # 等级, 薪资
    def __init__(self, name, age, sex, level, sal):
        super().__init__(name, age, sex)
        self.level = level
        self.sal = sal


class OldboyStudent(OldboyPeople):
    # 课程
    def __init__(self, name, age, sex, course):
        super().__init__(name, age, sex)
        self.course = course

    def choose_course(self):
        print(f'学生{self.name}选择课程{self.course}')


# print(super)
tea1 = OldboyTeacher('tank', 17, 'male', 9, '3.0')
stu1 = OldboyStudent('小健健', 20, 'female', 'python')
print(tea1.name, tea1.level)
print(stu1.name, stu1.course)
stu1.choose_course()

运行结果:
tank 9
小健健 python
学生[小健健]选择课程[python]

五、新式类与经典类:

新式类:继承object的类都称之为新式类。Python3中,所有的类是新式类,子类不继承自定义的类,默认继承object。

经典类:Python2中,凡是没有继承object的类都是经典类。

class Foo(object):
    pass
class Goo(Foo):
    pass
print(Foo.__bases__)  #(<class 'object'>,)
print(Goo.__bases__)  #(<class '__main__.Foo'>,)

mro():属于object-->type的函数,在多继承情况下,用来查看当前类的继承顺序

钻石继承也可以称之为菱形继承。在多继承的情况下形成的钻石继承(继承顺序)

--经典类:深度优先

--新式类:广度优先

#验证深度和广度查找顺序
class A:
    def test(self):
        print('from A')
    pass

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

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

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

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

class F(D,E):
    def test(self):
        print('from F')
    pass
f1=F()
f1.test()

# 新式类:F-D-B-E-C-A-object

# 经典类:F-D-B-A-E-C

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

import json
from datetime import date,datetime

print(json.JSONEncoder)
print(datetime.today()) #当前时间
print(date.today()) #当前日期

#“datetime”的对象是不可序列化的JSON,开发者角度,直接转成str.
dict1={
    'name':'tank',
    'today':str(datetime.today()),
    'today2':str(date.today())
}
res=json.dumps(dict1)
print(res)

运行结果:
<class 'json.encoder.JSONEncoder'>
2019-10-10 18:35:22.573824
2019-10-10
{"name": "tank", "today": "2019-10-10 18:35:22.573824", "today2": "2019-10-10"}
#isinstance:python内置的函数,可以传两个参数,判断参数一是否是参数二的一个实例。

#开源者的角度:修改json 代码
import json
from datetime import date,datetime
class MyJson(json,JSONEncoder):
     def default(self,o):
         #子类派生的功能
         #判断o是否是datetime的一个实例
         if isinstance(o,datetime):
             return o.strftime('%Y-%m-%d %X')
         elif isinstance(o,date):
             return o.strftime('%Y-%m-%d')
         else:
             #继承父类的default方法的功能
             return super().default(self,o)

dict1 = {
    'name': 'tank',
    'today': datetime.today(),
    'today2': date.today()
}

res = json.dumps(dict1, cls=MyJson)  # cls=None,默认指向的是原json的JSONEncoder
print(res)
运行结果:
{"name": "tank", "today": "2019-10-10 18:56:06", "today2": "2019-10-10"}

猜你喜欢

转载自www.cnblogs.com/lidandanaa/p/11649961.html