美文网首页
Python基础33-面向对象(继承资源(属性与方法)的使用注意

Python基础33-面向对象(继承资源(属性与方法)的使用注意

作者: Jacob_LJ | 来源:发表于2018-06-04 23:28 被阅读11次

    Python基础-面向对象

    在Python中, 继承是指子类对父类资源的使用权

    1 继承-属性与方法的使用权限

    1.1 测试属性与方法分别如下

    • 公有属性/方法
    • 受保护属性/方法
    • 私有属性/方法
    class Animal:
        a = 1 # 公有属性
        _b = 2 # 受保护属性
        __c = 3 # 私有属性
    
        #公有方法
        def t1(self):
            print("t1")
    
        # 受保护方法
        def _t2(self):
            print("t2")
        
        # 私有方法
        def __t3(self):
            print("t3")
        # 内置方法
        def __init__(self):
            print("init, Animal")
    
    
    class Person(Animal):
    
        # 在实例对象(子类)内对以上属性及方法的访问权限
        def test(self):
            print(id(self.a)) # 打印地址的目的是为了证明子类对父类属性继承是`可以使用`,而非`拥有副本`
            print(self.a)
            print(self._b)
            # print(self.__c) # 不能访问私有属性
    
            self.t1()
            self._t2()
            # self.__t3() # 不能访问私有方法
            self.__init__() 
    
    p = Person()
    p.test()
    
    print(id(Animal.a))
    p.test()
    
    >>>> 打印结果
    init, Animal
    4502964848
    1
    2
    t1
    t2
    init, Animal
    4502964848
    4502964848
    1
    2
    t1
    t2
    init, Animal
    
    

    除私有的属性和私有的方法, 其他属性和方法子类基本都能继承(具有使用权)

    2 继承-通过子类给父类属性进行赋值时,默认是指给之类增加一个与父类同名的属性

    class Father:
        age = 10
    
    
    class Son(Father):
        pass
    
    
    print(Son.age) # 访问父类属性
    Son.age = 9 # 给子类增加与父类同名属性
    
    print(Son.age)
    
    print(Father.age)
    print(Son.__dict__)
    print(Father.__dict__)
    
    >>>>打印结果
    10
    9
    10
    {'__module__': '__main__', '__doc__': None, 'age': 9}
    {'__module__': '__main__', 'age': 10, '__dict__': <attribute '__dict__' of 'Father' objects>, '__weakref__': <attribute '__weakref__' of 'Father' objects>, '__doc__': None}
    
    

    3 继承的3种形态

    继承的3种形态

    4 几种形态应该遵循的标准原则

    4.1 单继承

    • 遵循"从下到上的原则"
    • 自己身上没有这个资源, 就到父类里面去找,父类里面没有再往上找

    4.2 无重叠的多继承

    • 遵循"单调原则"
    • 按照继承的先后顺序,优先调用左侧继承链上的资源

    4.3 有重叠的多继承

    • 遵循"从下到上的原则"
    • 简单理解就是:
    1. A继承B继承C
    2. B重写了C类的方法, 那么A优先使用B类的方法

    4 查看类的资源查找顺序方法

    通过inspect模块进行

    目的:假如继承链中多个父类重写的资源,要学会查找哪些类的重写资源会被优先调用

    # 导入资源查看模块 inspect
    import inspect
    
    
    class D(object):
        pass
    
    class B(D):
        pass
    
    
    class C(D):
        pass
    
    class A(B, C):
        pass
    
    # 方法一
    print(inspect.getmro(A))
    
    # 方法二
    print(A.__mro__)
    
    # 方法三
    print(A.mro())
    
    >>>>打印结果
    
    (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
    (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
    [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
    

    TODO:《 针对于几种标准原则的方案演化》

    1. 不同 Python 版本 MRO 原则
    2. 菱形继承链问题

    5 资源覆盖(MRO 优先级高的优先调用)

    5.1 原理

    1. 基于MRO的资源检索链
    2. 优先级高的类具有一个与优先级低的类一样的一个资源(属性或方法)
    3. 会先选择优先级高的资源 ,而摒弃优先级低的资源(造成"覆盖"的假象)
    class D(object):
        age = "d"
        pass
    
    class C(D):
        age = "c"
        def test(self):
            print("c")
        pass
    
    class B(D):
        # age = "b"
        def test(self):
            print("b")
        pass
    
    class A(B, C):
        pass
    
    a = A()
    a.test()
    
    print(A.mro())
    
    print(A.age)
    print(A().test())
    
    >>>>打印结果
    b
    [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
    c
    b
    None
    

    5.2 调用优先级高资源时,self 与 cls 的变化

    结论:谁调用,就是谁

    class D(object):
        pass
    
    class C(D):
        def test(self):
            print(self)
        pass
    
    class B(D):
        def test(self):
            print(self)
    
        @classmethod
        def test2(cls):
            print(cls)
        pass
    
    class A(B, C):
        pass
    
    A.test2()
    
    a = A()
    a.test()
    
    >>>>打印结果
    
    <class '__main__.A'>
    <__main__.A object at 0x1011b79b0>
    
    

    6 在低优先级类的方法中,通过"super"调用高优先级类的方法

    • Python3.x
    class B:
        a = 1
    
        def __init__(self):
            self.b = 2
            self.xxx = "123"
    
        def t1(self):
            print("t1")
    
        @classmethod
        def t2(cls):
            print(cls)
            print("t2")
    
        @staticmethod
        def t3():
            print("t3")
    
    
    class A(B):
        c = 3
    
        def __init__(self):
            super().__init__()
            self.e = "666"
    
        def tt1(self):
            print("tt1")
    
        @classmethod
        def tt2(cls):
            super().t2()
            print("tt2")
    
        @staticmethod
        def tt3():
            print("tt3")
    
        pass
    
    a = A()
    print(a.__dict__)
    
    print("-" * 20)
    A.tt2()
    
    >>>>打印结果
    {'b': 2, 'xxx': '123', 'e': '666'}
    --------------------
    <class '__main__.A'>
    t2
    tt2
    
    • Python2.2+
    class B:
        a = 1
    
        def __init__(self):
            self.b = 2
            self.xxx = "123"
    
        def t1(self):
            print("t1")
    
        @classmethod
        def t2(cls):
            print(cls)
            print("t2")
    
        @staticmethod
        def t3():
            print("t3")
    
    
    class A(B):
        c = 3
    
        def __init__(self):
            super(A, self).__init__()
            self.e = "666"
    
        def tt1(self):
            print("tt1")
    
        @classmethod
        def tt2(cls):
            super(A, cls).t2()
            print("tt2")
    
        @staticmethod
        def tt3():
            print("tt3")
    
        pass
    
    a = A()
    print(a.__dict__)
    
    print("-" * 20)
    A.tt2()
    
    >>>>打印结果
    {'b': 2, 'xxx': '123', 'e': '666'}
    --------------------
    <class '__main__.A'>
    t2
    tt2
    

    注意

    1. super 和父类(超类)没有实质性的关联
      仅仅是沿着MRO链条, 找到下一级节点
    2. 保证调用形式的统一
      要是类名调用, 全是类名调用
      要是super调用, 全是super调用
      (混合使用容易出现死循环)

    相关文章

      网友评论

          本文标题:Python基础33-面向对象(继承资源(属性与方法)的使用注意

          本文链接:https://www.haomeiwen.com/subject/taaksftx.html