|
|
发表于 2026-6-30 17:02:34
|
显示全部楼层
看完小甲鱼写的,对于钻石继承的第一个问题的打印顺序还是有懵,找Deepseek解析了一下。看完这段解析,如果看懂了,那后面的问题都能答出来了。
这个问题的核心在于:**MRO 决定的是 `super()` 调用“往里进”的顺序,而 `print` 写在 `super()` 后面,打印发生在“往外出”的时候。**
简单说:**调用链是“下潜”,打印链是“上浮”**。
---
## 一步步拆解执行过程(像 debugger 一样)
当你执行 `c = C()` 时,程序并不是按照“先 C 全部执行完,再 B1 全部执行完”的顺序,而是像钻套娃一样:
1. **进入 `C.__init__`**
执行到 `super().__init__()`,此时根据 MRO(C→B1→B2→A),`super()` 去找 **B1**。
**C 的 `print` 被暂停,还没执行。**
2. **进入 `B1.__init__`**
执行到 `super().__init__()`,根据 MRO,B1 的下一个是 **B2**。
**B1 的 `print` 被暂停,还没执行。**
3. **进入 `B2.__init__`**
执行到 `super().__init__()`,根据 MRO,B2 的下一个是 **A**。
**B2 的 `print` 被暂停,还没执行。**
4. **进入 `A.__init__`**
执行到 `super().__init__()`(调用 object,啥也不做),继续往下走,**执行 `print("哈喽,我是A~")`**。
**A 执行完毕,返回上一层(B2)。**
5. **回到 `B2` 的 `super()` 之后**
刚才卡在 `super()` 这里,现在继续往下走,**执行 `print("哈喽,我是B2~")`**。
**B2 执行完毕,返回上一层(B1)。**
6. **回到 `B1` 的 `super()` 之后**
继续往下走,**执行 `print("哈喽,我是B1~")`**。
**B1 执行完毕,返回上一层(C)。**
7. **回到 `C` 的 `super()` 之后**
继续往下走,**执行 `print("哈喽,我是C~")`**。
---
## 用一张图看懂
```
调用 super() 的顺序(下潜): C → B1 → B2 → A
↓ ↓ ↓ ↓
执行 print 的顺序(上浮): C ← B1 ← B2 ← A
```
但 A 在最底层,所以先打印 A,然后逐层“浮”上来打印 B2、B1、C。
---
## 为什么是 B2 先于 B1,而不是 B1 先于 B2?
因为你的继承顺序是 `class C(B1, B2)`,MRO 算法保证 **B1 在 B2 前面**。
所以在“下潜”时:C 先找 B1,B1 找 B2,B2 找 A。
在“上浮”时:A 回到 B2,B2 回到 B1,B1 回到 C。
所以打印时 **B2 比 B1 先打印**(因为 B2 比 B1 更深一层)。
---
## 如果我把 `print` 放在 `super()` 前面,结果会怎样?
你可以试试把代码改成这样:
```python
class B1(A):
def __init__(self):
print("哈喽,我是B1~") # 先打印
super().__init__() # 再调用
```
那么打印顺序就会变成 **C → B1 → B2 → A**,完美匹配 MRO。因为这时打印发生在“下潜”的路上。
---
## 一句话总结
> **MRO 决定的是 `super()` 找“下一个是谁”的顺序;而你看到的结果是 `print` 在递归返回时的顺序,所以恰好是 MRO 的倒序(除了最底层的 A)。** |
|