前言:
目前朋友们对“python继承属性”大概比较关怀,兄弟们都需要分析一些“python继承属性”的相关知识。那么小编在网上汇集了一些关于“python继承属性””的相关知识,希望大家能喜欢,看官们快快来学习一下吧!本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理
方法解析顺序(MRO)
关于多重继承,比较重要的是它的方法解析顺序(可以理解为类的搜索顺序),即MRO。这个跟类是新式类还是经典类有关,因为两者的搜索算法不同。
在Python2及以前的版本,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于新式类;反之,不由任意内置类型派生出的类,则称之为经典类
在Python3以后,没有该区分,所有的类都派生自内置类型object,不管有没有显式继承object,都属于新式类。
对于经典类,多重继承的MRO是深度优先,即从下往上搜索;新式类的MRO是采用C3算法(不同情况下,可表现为广度优先,也可表现为深度优先)。
C3算法表现为深度优先的例子:
# C3-深度优先(D -> B -> A -> C)class A: var = 'A var'class B(A): passclass C: var = 'C var'class D(B, C): passif __name__ == '__main__': # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>] print(D.mro()) # A var print(D.var)复制代码
C3算法表现为广度优先的例子:
# C3-广度优先(D -> B -> C -> A)class A: var = 'A var'class B(A): passclass C(A): var = 'C var'class D(B, C): passif __name__ == '__main__': # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] print(D.mro()) # C var print(D.var)复制代码
注:关于C3的详细算法本文不讨论,因为我也搞不懂(狗头保命)
菱形多重继承
其实菱形多重继承上面已经有例子了,就是C3算法表现为广度优先这个例子,画起图来是这样的:
菱形多重继承会导致的一个问题是A初始化了两次,如下:
class A: def say(self): print("A say")class B(A): def say(self): print("B say") A.say(self)class C(A): def say(self): print("C say") A.say(self)class D(B, C): def say(self): print("D say") B.say(self) C.say(self)if __name__ == '__main__': dd = D() dd.say()复制代码
如果只想调用一次A,可使用super方法:
class A: def say(self): print("A say")class B(A): def say(self): print("B say") super().say()class C(A): def say(self): print("C say") super().say()class D(B, C): def say(self): print("D say") super().say()if __name__ == '__main__': print(D.mro()) dd = D() dd.say()复制代码_init_ 与 super()
1.如果父类有init方法,子类没有,则子类默认继承父类的init方法
class A: def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def say(self): print("A say, a1: %s, a2: %s" % (self.a1, self.a2))class B(A): def say(self): print("B say, a1: %s, a2: %s" % (self.a1, self.a2))if __name__ == '__main__': # 因为B继承了A的init方法,所以也要传入 a1,a2参数 bb = B("10", "100") bb.say()复制代码
2.如果父类有init方法,子类也有,可理解为子类重写了父类的init方法
class A: def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def say(self): print("A say, a1: %s, a2: %s" % (self.a1, self.a2))class B(A): def __init__(self, b1): self.b1 = b1 def say(self): print("B say, b1: %s" % self.b1)if __name__ == '__main__': # 此处B重写了A的init方法,所以只需要传入b1参数,也没有拥有a1,a2属性 bb = B("10") bb.say()复制代码
3.对于第二点,为了能使用或者扩展父类的行为,更常见的做法是在重写init方法的同时,显示调用父类的init方法(意味传的参数要变成3个)。
# 三种写法class A: def __init__(self, a1, a2): self.a1 = a1 self.a2 = a2 def say(self): print("A say, a1: %s, a2: %s" % (self.a1, self.a2))class B(A): def __init__(self, b1, a1, a2): # 第一种写法: Python2的写法 # super(B, self).__init__(a1, a2) # 第二种写法(推荐):Python3的写法,与第一种等价 super().__init__(a1, a2) # 第三种写法:与前两种等价,不过这种需要显示调用基类,而第二种不用 # A.__init__(self, a1, a2) self.b1 = b1 def say(self): print("B say, a1: %s, a2: %s, b1: %s" % (self.a1, self.a2, self.b1))if __name__ == '__main__': # 此处B重写了A的init方法,所以只需要传入b1参数,也没有拥有a1,a2属性 bb = B("10", "100", "1000") bb.say()复制代码最后的提醒
注意 __init__ 方法不要写错,避免写成__ini__或者其他的,因为两个是在太像,出了问题很难排查(坑过两次)。
私信小编01即可获取大量Python学习资料
标签: #python继承属性