派生


派生

子类中新定义的属性的这个过程叫做派生,子类在使用派生的属性时始终以自己的为准。

class A1:
    x = 10


class B1(A1):
    x = 11  # 派生属性

    def f1(self):  # 派生方法
        pass


b = B1()
print(b.x)

11

派生类中使用父类的属性

  • 方式一:self,但这样如果子类中有相同属性,则会优先使用子类的属性,依赖继承关系。
class A1:
    def f1(self):
        print('AAAA')

class B1(A1):
    def f2(self):
        self.f1()
        
b = B1()
b.f2()

AAA
  • 方式二:指明道姓使用父类的属性,可以不依赖继承关系。
class A1:
    def f1(self):
        print('AAAA')
        
class B1:
    def f2(self):
        A1.f1(self)  # 通过类调用方法,此时为普通函数,需要向self传参。
        
b = B1()
b.f2()

AAAA
  • 方式三:使用内置函数super(),严格依赖继承关系。

super([type[, object-or-type]])

返回一个代理对象,该对象会参照发起属性查找的那个类的mro列表,去super当前所在类的父类中查找属性。即便并没有直接继承关系,super仍然会按照MRO列表继续往后查找。super不会从对象的名称空间和对象所属的父类内查找属性,而是直接从MRO列表的下一个类中查找。

在Python2中super的使用需要完整地写成super(自己的类名,self) ,而在python3中可以简写为super()。

class A1:
    def f1(self):
        print('AAAA')


class B1(A1):
    def f2(self):
        # 通过对象调用绑定方法会将对象传给self。
        super().f1()

b = B1()
b.f2()

使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

class A:
    def test(self):  # 对象obj和类C均没有test方法则会在父类中查找
        print('from A')  
        super().test()  # super会参照发起属性查找的类的mro列表,去super当前所在类的父类中查找属性。即便A和B并没有继承关系。
        
class B:
    def test(self):
        print('from B')
        
class C(A, B):
    pass

print(C.mro())
obj = C()
obj.test()

super会参照发起属性查找的类的mro列表,去super当前所在类的父类中查找属性。即便A和B并没有继承关系,也会去B中查找。

[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
from A
from B

更推荐使用super()来重用父类的方法,但不要同时使用两种方法。


类的特殊属性

#python为类内置的特殊属性
类名.__name__ # 类的名字(字符串)
类名.__doc__ # 类的文档字符串
类名.__base__ # 类的第一个父类
类名.__bases__ # 类所有父类构成的元组,仅查看直接父类。
类名.__dict__ # 类的属性字典
类名.__module__ # 类定义所在的模块
类名.__class__ # 实例对应的类(仅新式类中)

取值顺序

单继承:当前对象的名称空间 --> 子类名称空间 --> 父类 --> 父类的父类... --> object

class A1:
    def f1(self):
        print('A1.f1')

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


class B1(A1):
    def f1(self):
        print('B1.f1')

b = B1()
b.f2()

对象b会先在自身名称空间内查找,然后是子类,然后在父类内找到后即会执行f2(),第一行打印 ‘ A1.f2 ’ ,第二行又调用self.f1(),此时self为对象b,同样会先遵循取值顺序,对象 -》子类 -》父类 -》object。

A1.f2
B1.f1

多继承会有个取值问题,也就是当多个父类有相同属性的时候,会从哪里取值,这就是后面要说的菱形问题。

原文地址:https://www.cnblogs.com/ChiRou/p/14217835.html