zoukankan      html  css  js  c++  java
  • python基础语法15 面向对象2 继承,多态,继承json模块中JSONEncoder,并派生出新的功能

    继承

    1.什么是继承?
      继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或超类。

      - 在Python中,一个子类可以继承多个父类。(面试可能会问)
      - 在其它语言中,一个子类只能继承一个父类。

    2.继承的作用?
      减少代码的冗余。

    3.如何实现继承?
      1) 先确认谁是子类,谁是父类。
      2) 在定义类子类时, 子类名(父类名)。

    # 父类
    class Father1:
        x = 1
        pass
    
    class Father2:
        pass
    
    class Father3:
        pass
    
    # 子类
    class Sub(Father1, Father2, Father3):
        pass
    
    # 子类.__bases__ 查看父类
    print(Sub.__bases__)
    print(Sub.x)

    寻找继承关系

    - 如何寻找继承关系:
      - 确认谁是子类
        - 胡晨阳对象 ---> 人子类 ---> 动物父类
        - 猪坚强对象 ---> 猪子类 ---> 动物父类
        - 哈士奇对象 ---> 狗子类 ---> 动物父类

        - 人、猪、狗 都是子类

      - 确认谁是父类
        - 动物类是父类

        - 得先抽象,再继承
          - 抽取对象之间相似的部分,总结出类
          - 抽取类之间相似的部分,总结出父类。

    继承可以解决代码冗余问题

    # 老男孩人类
    class OldboyPeople:
        school = 'oldboy'
        country = 'China'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    # 老师类
    class OldboyTeacher(OldboyPeople):
        # school = 'oldboy'
        # country = 'China'
    
        # 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(OldboyPeople):
        # school = 'oldboy'
        # country = 'China'
        #
        # def __init__(self, name, age, sex):
        #     self.name = name
        #     self.age = age
        #     self.sex = sex
        # 学生选择课程
        def choose_course(self):
            print(f'学生 {self.name} 正在选择课程...')
    
    stu1 = OldboyStudent('YJG', 50, 'female')
    print(stu1.school, stu1.name, stu1.age, stu1.sex)
    tea1 = OldboyTeacher('大脸', 75, 'female')
    print(tea1.school, tea1.name, tea1.age, tea1.sex)

    注意: 程序的执行顺序是由上到下,父类必须定义在子类的上方。
    - 在继承背景下,对象属性的查找顺序:
      1.先从对象自己的名称空间中查找
      2.对象中没有,从子类的名称空间中查找。
      3.子类中没有, 从父类的名称空间中查找,若父类没有,则会报错!

    class Goo:
        x=10
    
    class Foo(Goo):
        X=100
    
    foo_obj = Foo()
    print(foo_obj.x)    # 10
    print(foo_obj.__dict__) # {}
    print(Foo.__dict__) # {'__module__': '__main__', 'X': 100, '__doc__': None}
    print(Goo.__dict__) # {'__module__': '__main__', 'x': 10, '__dict__':
    # <attribute '__dict__' of 'Goo' objects>, '__weakref__': <attribute '__weakref__' of 'Goo' objects>, '__doc__': None}
    
    foo_obj.x = 1000
    print('子类的名称空间',Foo.__dict__)   # 子类的名称空间 {'__module__': '__main__', 'X': 100, '__doc__': None}
    print('对象的名称空间',foo_obj.__dict__)   # 对象的名称空间 {'x': 1000}

    派生:

      指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。
      若子类中的方法名与父类的相同,优先用子类的。

    # 父类
    class Foo:
        def f1(self):
            print('from Foo.f1...')
    
        def f2(self):  # self ---> bar_obj
            print('from Foo.f2...')
            # bar_obj.f1() ---> 对象自己找 ---> Bar ---> Foo
            self.f1()  # 对象的f1,而非类的f1
    
    # 子类
    class Bar(Foo):
    
        # 重写
        def f1(self):
            print('from Bar.f1..')
    
        def func(self):
            print('from Bar.func...')
    
    # bar_obj = Bar()
    # bar_obj.f1()  # from Bar.f1..
    # bar_obj.func()  # from Bar.func...
    # bar_obj.f2()  # from Foo.f2...
    
    # 派生后继承关系查找验证:
    bar_obj = Bar()
    '''
    结果1: 
        from Foo.f2...
        from Bar.f1...
    '''
    bar_obj.f2()

    - 子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法

    #方式一:
    class OldboyPeople:
        school = 'oldboy'
        def __init__(self, name, age, sex):  # self == tea1, name == 'tank', age == 17, sex == 'male'
            self.name = name
            self.age = age
            self.sex = sex
    class OldboyTeacher(OldboyPeople): # tea1, 'tank', 17, 'male', 15000000 def __init__(self, name, age, sex, sal): # self.name = name # self.age = age # self.sex = sex # 类调用类内部的__init__,只是一个普通函数 # OldboyPeople.__init__(tea1, 'tank', 17, 'male') OldboyPeople.__init__(self, name, age, sex) self.sal = sal
    def change_score(self): print(f'老师 {self.name} 修改分数...') class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, girl): OldboyPeople.__init__(self, name, age, sex) self.girl = girl def choose_course(self): print(f'学生 {self.name} 选择课程...') tea1 = OldboyTeacher('tank', 17, 'male', 15000000) print(tea1.name, tea1.age, tea1.sex, tea1.sal) stu1 = OldboyStudent('姚玉鑫', 28, 'male', '凤姐') print(stu1.name, stu1.age, stu1.sex, stu1.girl)
    # 方式二:
    class OldboyPeople:
        school = 'oldboy'
        # self == tea1
        def __init__(self, name, age, sex):  # self == tea1, name == 'tank', age == 17, sex == 'male'
            self.name = name
            self.age = age
            self.sex = sex
    
    class OldboyTeacher(OldboyPeople):
        # tea1, 'tank', 17, 'male', 15000000
        def __init__(self, name, age, sex, sal):
            # super() ---> 特殊的对象 ---> 对象.属性 ---> 父类的名称空间
            # 会将调用类传入的对象当做第一个参数传给__init__()
            super().__init__(name, age, sex)
            self.sal = sal
    
        def change_score(self):
            print(f'老师 {self.name} 修改分数...')
    
    
    class OldboyStudent(OldboyPeople):
    
        def __init__(self, name, age, sex, girl):
            super().__init__(name, age, sex)
            self.girl = girl
        def choose_course(self):
            print(f'学生 {self.name} 选择课程...')
    
    tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
    print(tea1.name, tea1.age, tea1.sex, tea1.sal)
    
    stu1 = OldboyStudent('姚玉鑫', 28, 'male', '凤姐')
    print(stu1.name, stu1.age, stu1.sex, stu1.girl)

    经典类与新式类: (了解)
      - 工作中遇不到
      - 面试有可能会问

    - 新式类:
      1.凡是继承object的类或子孙类都是新式类。
      2.在python3中所有的类都默认继承object。

    - 经典类:
      1.在python2中才会有经典类与新式类之分。
      2.在python2中,凡是没有继承object的类,都是经典类。

    调用mro返回的是一个继承序列: (了解知识点)
    super的继承顺序严格遵循mro继承序列。

    super严格遵循mro继承顺序

    调用mro返回的是一个继承序列: (了解知识点)
      super的继承顺序严格遵循mro继承序列。

    class Father1:
        x = 10
        pass
    
    class Father2:
        x=20
        pass
    
    # 多继承的情况下: 从左到右
    class Sub(Father1,Father2):
        # 注意: __int__ 不是 __init__
        def __init__(self):
            print(super().__delattr__)
    
    print(Sub.mro())    # 显示继承顺序
    # [<class '__main__.Sub'>, <class '__main__.Father1'>, <class '__main__.Father2'>, <class 'object'>]
    obj=Sub()   # <method-wrapper '__delattr__' of Sub object at 0x0000000009B758D0>
    print(object)

    在python3中提供了一个查找新式类查找顺序的内置方法.
      mro(): 会把当前类的继承关系列出来。

    class Father1:
        x = 10
        pass
    
    class Father2:
        x=20
        pass
    
    # 多继承的情况下: 从左到右
    class Sub(Father1,Father2):
        # 注意: __int__ 不是 __init__
        def __init__(self):
            print(super().__delattr__)
    
    print(Sub.mro())    # 显示继承顺序
    # [<class '__main__.Sub'>, <class '__main__.Father1'>, <class '__main__.Father2'>, <class 'object'>]
    obj=Sub()   # <method-wrapper '__delattr__' of Sub object at 0x0000000009B758D0>
    print(object)

    在python3中提供了一个查找新式类查找顺序的内置方法.
      mro(): 会把当前类的继承关系列出来。

    # 注意: super()会严格按照mro列表的顺序往后查找
    class A:
        def test(self):
            print('from A.test')
            super().test()  # 调用对象的父级,非A类的父级
    
    class B:
        def test(self):
            print('from B.test')
    
    class C(A, B):
        pass
    
    c = C()
    # 检查super的继承顺序
    print(C.mro())
    
    # 去A找,有的话打印,然后super又执行了test,根据mro中查找打印B类中test。
    c.test()
    '''
    from A.test
    from B.test
    '''

    多继承情况下造成 “钻石继承”

      mro的查找顺序:
        - 新式类:
          - 广度优先:从左面第一条链往后查找,如果找到公共继承对象,跳过往右一条链继续往后查找

        - 经典类:
          - 深度优先:从左面第一条链往后查找,一直查到低,再往右从第二条一直查到底...

    面试注意细节:
      - 遇到一个技术 知道是什么,但是不会用,一定要贬低这个技术,觉得很简单,让面试官误以为你很会。
      - 遇到一个技术,不知道是什么,要说我见过,但是忘记怎么用了,我博客里面,回头找一下就行了

     

    # 了解:
    # 新式类:
    class A(object):
        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
    # F-->D-->B-->E-->C-->A-->object
    print(F.mro())
    obj=F()
    obj.test()  # from B

     继承json模块中JSONEncoder,并派生出新的功能。

    import json
    from datetime import date, datetime
    
    # 在原来json模块中可序列化的数据类型优先
    # <class 'datetime.datetime'>  date
    # print(type(datetime.now()))
    #
    # dict1 = {
    #     # 'time1': str(datetime.now())
    #     'time1': datetime.now()
    # }
    #
    # res = json.dumps(dict1)
    # print(res)  # 'datetime' is not JSON serializable
    
    class MyJson(json.JSONEncoder):
        # datetime.now() ---> o
        def default(self, o):
            # isinstance: 判断一个对象是否是一个类的实例
            if isinstance(o, datetime):  # True
                return datetime.strftime(o, '%Y-%m-%d %X')
    
            else:
                return super().default(self, o)
    
    dict1 = {
        # 'time1': str(datetime.now())
        'time1': datetime.now(),
        'name': 'tank'
    }
    
    # 指定自定义的一个MyJson  派生类
    # cls=自定义的类
    res = json.dumps(dict1, cls=MyJson)
    print(res)  # {"time1": "2019-11-27 14:24:39", "name": "tank"}
  • 相关阅读:
    当Django模型迁移时,报No migrations to apply 问题时
    django--各个文件的含义
    django--创建项目
    1013. Battle Over Cities (25)
    1011. World Cup Betting (20)
    1009. Product of Polynomials (25)
    1007. Maximum Subsequence Sum (25)
    1006. Sign In and Sign Out (25)
    1008. Elevator (20)
    1004. Counting Leaves (30)
  • 原文地址:https://www.cnblogs.com/ludingchao/p/11935964.html
Copyright © 2011-2022 走看看