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"}
  • 相关阅读:
    分享15款为jQuery Mobile定制的插件
    显​示​器​分​辨​率​调​高​后​黑​屏​的​最​佳​解​决​办​法
    out 和 ref 之间的区别整理
    赋值操作符重载
    最长公共子串
    最长递增子序列
    动态规划
    Eclipse支持Jquery代码提示(JqeuryWTP)
    ubuntu10.04编译内核不显示grub菜单解决
    CSS水平导航条和纵向导航条
  • 原文地址:https://www.cnblogs.com/ludingchao/p/11935964.html
Copyright © 2011-2022 走看看