关于python的多继承的一些思考,以及多继承时属性丢失问题的解决方法

最近在给孩子编写一款小游戏的时候发现了一个 问题,某些子类调用父类属性时会报错,提示未找到该属性。当时我很纳闷,就在网上搜索一些相关资料发现这方面的资料很少。所以今天就写下来 希望能帮到有需要的朋友。

ok,我们先随便写上几个类

class A():
	def __init__(self):
		self.aa = 11

class B():
	def __init__(self):
		self.bb = 22

class C(A,B):
	def __init__(self):
		self.cc = 33

c = C()
print(c.aa, c.bb, c.cc)

运行以后得到的提示为

Traceback (most recent call last):
  File "/Users/yansong/Desktop/fjdz-new/test.py", line 17, in <module>
    print(c.aa, c.bb, c.cc)
AttributeError: 'C' object has no attribute 'bb'
Process finished with exit code 1

这里提示没有bb这个属性,到这里我非常纳闷,明明已经继承了啊。

于是我去研究了一下python的继承逻辑。Python使用MRO(method resolution order方法解析顺序)解决基类搜索顺序问题。这里参考了https://blog.csdn.net/u013008795/article/details/90412084这篇文章

C3算法,解决了继承的单调性,它阻止创建之前版本产生二义性的代码。求得的MRO本质是为了线性化,且确定 了顺序。

单调性:假设有A、B、C三个类,C的mro是[C, A, B],那么C的子类的mro中,A、B的顺序一致就是单调的

也就是说子类继承于多个父类,__init__,是按继承顺序,哪个父类在最前面且有自己的__init__,则继承它;若最前面的父类无__init__,则继承第二个父类的__init__,若还是无__init__,则依次往后寻找,直到继承的某个父类含__init__。

所以问题就出在这里,当C执行了父类A的构造器__init__()时,就不会执行B的构造器__init__()了。

于是我更改了一下继承顺序

class A():
	def __init__(self):
		self.aa = 11

class B():
	def __init__(self):
		self.bb = 22

class C(A,B):
	def __init__(self):
		super().__init__()
		B.__init__(self)
		self.cc = 33

现在我们再来打印一下之前无法找到的那个属性。

c = C()
print(c.bb)

果然打印出来了


22
Process finished with exit code 0

ok到目前为止,我们现在已经解决了调用之前无法找到属性。可是,如果我们如果想让两个父类的属性都被调用改怎么办呢??

其实办法也很简单,就是在子类的构造器里显式的调用一遍另一个负累的构造器。ok我们回到最初那段代码来试试

class A():
	def __init__(self):
		self.aa = 11

class B():
	def __init__(self):
		self.bb = 22

class C(A,B):
	def __init__(self):
		super().__init__() 
		B.__init__(self)  #这里 我们显式的调用父类B的构造器
		self.cc = 33

c = C()
print(c.aa, c.cc, c.bb)

结果为


11 33 22
Process finished with exit code 0

大功告成。到这里,基本上我们就解决了多继承时父类属性丢失的问题。

希望能对有同样问题的朋友们有一点帮助。最后说一句,多继承方案,其实并不是一个高效的方案,很多语言都不支持多继承,比如java,因为这样会增加后期维护,以及查找错误的难度。所以,慎用!!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Python中的多继承构造方法是指在一个类继承多个父类,如何处理构造方法。在Python中,一个类的构造方法是通过`__init__`方法来定义的。当一个子类继承多个父类,它的构造方法可以通过调用父类的构造方法来初始化父类属性。通常使用`super`函数来实现这一点。`super`函数用于调用父类方法,可以在子类的构造方法中使用`super().__init__()`来调用父类的构造方法,从而完成对父类属性的初始化。引用中提到了`super`函数和构造方法的相关内容。例如,如果有一个子类`MyClass`继承了多个父类,并且每个父类都有自己的构造方法,可以在子类的构造方法中使用`super().__init__()`来依次调用父类的构造方法,从而完成对父类属性的初始化。引用中给出了一个带有多个参数的构造方法的示例代码。在这个示例中,`MyClass`的构造方法接受一个参数`name`,并将其赋值给`self.name`。在实例化对象,可以通过传递参数的方式给构造方法传递参数。最后,引用中提到了继承的概念,即一个类可以继承另一个类的属性方法。在Python中,所有的类都默认继承自`object`类。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【详解】Python中的(多)继承、__init__、__new__、super](https://blog.csdn.net/LittleSeedling/article/details/122798938)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [0804Python总结-单继承,多继承,菱形继承,__init__魔术方法(构造方法)](https://blog.csdn.net/qq_45957580/article/details/107827951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值