直接赋值__bases__会失败,因为Python将__bases__设为只读属性以保障MRO一致性和类完整性,强行修改抛出TypeError;正确替代方案是用types.new_class()动态构造新类。

不能安全地通过直接赋值 __bases__ 来动态修改类的基类继承关系——Python 明确禁止对大多数内置类型和普通类的 __bases__ 进行写操作,强行尝试会抛出 TypeError: __bases__ assignment is not supported。
为什么直接赋值 __bases__ 会失败
Python 在 CPython 实现中将 __bases__ 设为只读属性(除非满足极特殊条件),这是为了保障 MRO(Method Resolution Order)的一致性和类对象的完整性。即使类没有被冻结或使用 __slots__,只要它不是“用户定义的新式类且所有父类都是可变的”,__bases__ 就不可写。
- 常见错误现象:
TypeError: __bases__ assignment is not supported - 仅在极少数情况下允许修改:类必须是纯 Python 定义、所有父类都未被冻结、且不涉及
builtins.object以外的内置类型(如list,dict等作为父类时必然失败) - 即便技术上可行(比如某些空类),修改后可能破坏 MRO 缓存,导致
super()行为异常或方法查找错乱
替代方案:用 types.new_class() 构造新类
如果目标是“让一个类表现出继承了新父类的行为”,正确做法是基于原类动态构造一个新类,而不是篡改已有类。这比硬改 __bases__ 更可靠、更符合 Python 的对象模型。
- 使用
types.new_class(name, bases, kwds, exec_body)创建带指定基类的新类 -
bases参数接受元组,例如(OriginalClass, NewParent)或(NewParent, OriginalClass),顺序影响 MRO - 若需保留原类的属性和方法,可在
exec_body中手动复制,或用type(name, bases, dict(OriginalClass.__dict__))(注意:跳过__dict__中的描述符和不可序列化项) - 示例:
import types class A: pass class B: pass C = types.new_class('C', (A, B), {}) # 等效于 class C(A, B): pass
真正需要运行时“切换”行为时,优先考虑组合或协议
试图动态改继承,往往说明设计上更适合用组合(composition)或鸭子类型(duck typing)来解耦行为变化。硬改继承关系既难维护,又容易引发难以调试的 MRO 冲突。
立即学习“Python免费学习笔记(深入)”;
- 比如想让某个实例临时获得某能力,不如用
setattr(obj, 'method_name', lambda ...)或委托给策略对象 - 若需多态,用抽象基类(ABC)+
register()注册,比改__bases__更清晰、更易测试 - 元类虽能干预类创建过程,但用于“运行时改继承”属于过度设计,且无法作用于已存在的类实例
真正要改继承关系的地方极少,绝大多数场景下,要么用 types.new_class() 生成新类,要么重构为组合——直接动 __bases__ 不仅大概率失败,而且成功了也大概率埋雷。


















