
本文详解如何在多重继承中通过 `super()` 协作式初始化多个父类,强调关键字参数解耦、mro 链式调用和 `**kwargs` 传递机制,并提供可直接运行的规范示例。
在 Python 中实现多重继承时,若子类需同时初始化两个或多个父类(如 Place 和 Product),直接硬编码调用 Parent.__init__(self, ...) 或错误使用 super(ClassName, self) 是不可靠且易出错的。你遇到的 TypeError: super() argument 1 must be type, not str 正源于 super(Place).__init__(...) 这一非法写法——super() 的第一个参数必须是类对象(如 Place),而非字符串,且更关键的是:super() 的设计初衷并非用于显式指定某个父类,而是按 MRO(Method Resolution Order)自动委托给下一个协作类。
✅ 正确做法是采用 协作式初始化(cooperative initialization):所有参与多重继承的类统一使用 super().__init__(**kwargs),并约定仅接收自身关心的关键字参数,将剩余参数(**kwargs)无损传递下去,最终由 object.__init__() 终止链式调用。
✅ 规范实现步骤
- 所有 __init__ 方法使用关键字-only 参数(* 后参数),明确职责边界;
- 每个类只处理自己需要的参数,其余全交由 `super().init(kwargs)` 向下传递**;
- 子类 __init__ 不显式调用任一父类构造器,仅调用一次 `super().init(kwargs)`**;
- 确保 MRO 合理(可通过 Flat.__mro__ 查看:(Flat, Place, Product, object))。
以下是重构后的可运行代码:
class Place:
def __init__(self, *, country, city, **kwargs):
super().__init__(**kwargs) # 委托给下一个 MRO 类(Product → object)
self.country = country
self.city = city
def show_location(self):
print(self.country, self.city)
class Product:
def __init__(self, *, price, currency='$', **kwargs):
super().__init__(**kwargs) # 委托给 object(最终接收空 kwargs)
self.price = price
self.currency = currency
def show_price(self):
print(self.price, self.currency)
class Flat(Place, Product):
def __init__(self, *, street, number, **kwargs):
super().__init__(**kwargs) # 启动 MRO 链:Flat → Place → Product → object
self.street = street
self.number = number
def show_address(self):
print(self.number, self.street)
# ✅ 正确调用:全部使用关键字参数,无需关心顺序
myflat = Flat(
country='Mozambique',
city='Nampula',
street='Rua dos Combatentes',
number=4,
price=150000,
currency='USD'
)
myflat.show_location() # Mozambique Nampula
myflat.show_price() # 150000 USD
myflat.show_address() # 4 Rua dos Combatentes⚠️ 注意事项与常见误区
- ❌ 不要在 Flat.__init__ 中写 Place.__init__(self, ...) 或 Product.__init__(self, ...):这会破坏 MRO,导致某一方未被初始化或重复初始化;
- ❌ 不要混合位置参数与 **kwargs(如原问题中 country, city, street, number, price 混排):易引发参数错位,且无法适配协作式调用;
- ✅ *必须使用 `` 强制关键字参数**:这是实现参数解耦和可维护性的关键约束;
- ? 可随时检查 MRO:print(Flat.__mro__) 输出 (
ain__.Flat'>, , , ),验证调用顺序; - ? 若无法修改现有父类(如第三方库类),应创建适配器类(Adapter) 封装其 __init__,使其符合协作协议(详见 Raymond Hettinger 经典文章 Python’s super() considered super!)。
✅ 总结
super() 在多重继承中不是“调用父类”的快捷方式,而是构建可组合、可扩展、可预测的初始化链的核心机制。它要求所有参与者共同遵守契约:只取所需、余者尽传、统一委托。遵循此模式,你的 Flat 类才能真正兼具 Place 的地理属性与 Product 的商业属性,而不会陷入初始化混乱或运行时错误。
立即学习“Python免费学习笔记(深入)”;










