Monkey Patch类的父类后子类未继承新父类属性的解决方法
问题:替换父类后子类未继承新父类的属性?
首先先还原你的代码场景:
module.py中的代码:
class A(): a = 1 class B(A): b = 2
主文件中的代码:
import module class C(): c = 3 module.A = C # 执行后报错 assert module.B().c == 3 # AttributeError: 'B' object has no attribute 'c'
为什么会出现这个问题?
Python中,当你定义class B(A)时,在类定义的那一刻,Python就把B的父类(存储在B.__bases__属性里)绑定到了当时的A类对象。之后你把module.A重新赋值为C,只是改变了module命名空间里A这个变量的指向,但B内部已经固定的父类引用并没有被更新——它依然指向最初定义的那个A类,完全不知道你把module.A换成了C。
解决办法
方法1:直接修改子类的__bases__属性
这是最直接有效的方案,手动更新B的父类列表,让它指向新的C类:
import module class C(): c = 3 # 两步操作:替换module.A的指向,同时更新B的父类 module.A = C module.B.__bases__ = (C,) # 将B的父类从原来的A改为C # 现在断言可以正常通过 assert module.B().c == 3
方法2:设计动态可切换的父类(适合复杂场景)
如果你的业务场景需要频繁切换父类,或者希望父类的变化能自动同步到子类,可以在定义B的时候用动态获取父类的方式,比如借助函数或者元类:
修改后的module.py:
class A(): a = 1 # 用一个函数来提供父类,方便后续修改 def get_base_class(): return A # 定义B时,通过函数获取父类 class B(get_base_class()): b = 2
主文件中的操作:
import module class C(): c = 3 # 先修改父类的获取逻辑 module.get_base_class = lambda: C # 重新定义B类,让它继承新的父类 module.B = type('B', (module.get_base_class(),), {'b': 2}) assert module.B().c == 3
这种方法相对灵活,但需要额外的代码设计,如果只是临时替换父类,方法1足够简单高效。
内容的提问来源于stack exchange,提问作者Vasco
相关产品推荐
相关产品推荐

