发布网友 发布时间:2022-04-18 20:19
共8个回答
懂视网 时间:2022-04-19 00:40
注:此处以python 3为运行环境,例子摘自《python cookbook》第8章。Python代码
class Base:
def __init__(self):
print('Base.__init__')
class A(Base):
def __init__(self):
Base.__init__(self)
print('A.__init__')
class B(Base):
def __init__(self):
Base.__init__(self)
print('B.__init__')
class C(A,B):
def __init__(self):
A.__init__(self)
B.__init__(self)
print('C.__init__')
此时实例化C类会输出如下:
Python代码
>>> c = C()
Base.__init__
A.__init__
Base.__init__
B.__init__
C.__init__
>>>
从中可看出Base类被调用了两次。这想必在很多情况下都不是我们想要的结果,所以此时可考虑用super方法。
2、利用super的情况:
Python代码
class Base:
def __init__(self):
print('Base.__init__')
class A(Base):
def __init__(self):
super().__init__()
print('A.__init__')
class B(Base):
def __init__(self):
super().__init__()
print('B.__init__')
class C(A,B):
def __init__(self):
super().__init__() # Only one call to super() here
print('C.__init__')
此时再实例化C类的输出为:
Python代码
>>> c = C()
Base.__init__
B.__init__
A.__init__
C.__init__
>>>
可看出Base类是不是只调用了一次啊!但很遗憾的是,这并不是促使我写这篇博客记录的原因,因为如果仔细观察的话,虽说Base类的确如预期只调用了一次,但你有没有发觉是先输出“B.__init__”而后才输出的“A.__init__”?而且为什么这样就使得Base只初始化了一次?想必你也有点懵逼了吧?其实这一切都得“怪罪”于super在多继承时的调用过程。python在实现一个类(不仅是继承)时,会产生一个方法生成解析顺序列表,该列表可通过类属性 __mro__ 查看之,如本例中是这样的:
Python代码
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
<class '__main__.Base'>, <class 'object'>)
>>>
所以在搜索一个属性或方法时,它就会按照这个列表遍历每个类,直到找到第一个匹配这个属性或方法的类为止。而在继承中使用super时,解释器会每遇到一次super就会在该列表上搜索下一个类,直到不再遇到super或列表遍历完为止,然后再类似递归逐层返回。因此本例中搜索过程为:C中遇到super --> 搜索列表中的下一个类,即A --> A中再次遇到super,搜索B --> B中super再现,搜索Base --> 初始化Base类,递归返回。
为了更好的解释该过程,现在请注释掉B类的super所在行:
Python代码
class B(Base):
def __init__(self):
#super().__init__()
print('B.__init__')
class C(A,B):
def __init__(self):
super().__init__() # Only one call to super() here
print('C.__init__')
再次实例化C类,输出如下:
Pythonn代码
>>> c = C()
B.__init__
A.__init__
C.__init__
Base类不再产生输出!为什么?因为B中没了super后,就阻断了列表去搜索Base类,所以也就没有初始化Base了!
热心网友 时间:2022-04-18 21:48
这位同学,想必你是刚刚学java,你这个问题在java中是不会出现的,你看看B继承A,C继承B,你说程序会这么写吗? 既然Java是单继承的,想实现多继承直接使用接口好了,何必这样子呢。程序太不美观了,以后写代码不可能写成这样子的。热心网友 时间:2022-04-18 23:06
如果父类有无参构造方法,即使没有显式调用super()的话,也会自动调用super()的。热心网友 时间:2022-04-19 00:41
其实这。。不就是super().super()吗?热心网友 时间:2022-04-19 02:32
同样是super();,当你调用B的构造函数时,B又调用了A的构造函数。追问我说的是B的构造方法里面除了super()外的其他内容都不要执行,而是仅仅调用A的构造方法追答参考楼上 软件工程师杜天微
热心网友 时间:2022-04-19 04:40
子类只能调用自己直接父类的构造方法~追问只能?!能不能说清楚些,我觉得“软件工程师杜天微”说的也挺有道理的追答.我和他说的完全是一个意思啊 c类只能决定调用b类的构造方法 而调用a类的构造方法只能又b类来决定
热心网友 时间:2022-04-19 07:05
只有super().这是递归调用.热心网友 时间:2022-04-19 09:46
同样是 super();追问我说的是仅仅调用A的无参构造方法。如果是这样,那要是调用B的无参构造呢?是不是也是同样是super()呢?追答你new C的时候,不可能不构建B而直接构建C。
构建C的顺序是 先按照C的大小分配内存 内存的首先构建A,然后构建B,最后才是C。
要构造A,首先要构造B;构造因为你B只有无参构造,所以也只能调用这个。。。
如果你B里面有个
B(String s){ super(); }
那也可以
C(){
super("123");
}