You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修改sys.modules[__name__]后调用父类方法报错的技术问询

问题分析与解决方案

这个问题的核心原因是当你将sys.modules[__name__]替换为Child实例后,原模块对象失去了唯一引用,被Python的垃圾回收机制销毁,导致模块级别的Child和Parent类定义也被回收。当你调用module1.my_method()时,Child实例的方法试图引用全局作用域中的Child类(也就是super(Child, self)里的Child),但此时这个类已经不存在了,从而引发报错。

为什么会这样?

Python加载模块时,会创建一个模块对象并将其存入sys.modules。当你执行sys.modules[__name__] = Child(__name__),你替换了sys.modules中该模块的条目为Child实例,原模块对象因为没有其他引用会被GC回收。而模块中定义的Parent、Child类都属于原模块对象的全局命名空间,会随模块对象销毁而消失。此时Child实例的my_method方法在调用super(Child, self)时,找不到Child类的引用,就会抛出错误。

解决方案

这里提供几种可行的修复方案:

方案1:直接调用父类方法,不使用super

既然super需要依赖类的引用,我们可以绕过super,直接显式调用父类的方法并传入self:

class Parent(object):
    def my_method(self):
        print 'Hello World'

class Child(Parent):
    def __init__(self, name):
        self.name = name
    def my_method(self):
        # Do something
        Parent.my_method(self)  # 直接调用父类方法
        # Do something more

import sys
sys.modules[__name__] = Child(__name__)

这种方式不需要依赖Child类的引用,直接通过父类调用,避免了全局类引用被回收的问题。

方案2:将类引用保存到实例属性中

我们可以在Child实例中保存Child类的引用,这样即使原模块对象被回收,实例依然持有类的引用,super调用就能正常工作:

class Parent(object):
    def my_method(self):
        print 'Hello World'

class Child(Parent):
    def __init__(self, name):
        self.name = name
        self._child_class = Child  # 保存类引用到实例属性
    def my_method(self):
        # Do something
        super(self._child_class, self).my_method()  # 使用实例中保存的类引用
        # Do something more

import sys
sys.modules[__name__] = Child(__name__)

这样super调用依赖的是实例持有的类引用,不会受原模块对象回收的影响。

方案3:保留原模块对象的引用

我们可以给原模块对象添加一个引用,防止被GC回收,这样模块级别的类定义就会保留:

class Parent(object):
    def my_method(self):
        print 'Hello World'

class Child(Parent):
    def __init__(self, name):
        self.name = name
    def my_method(self):
        # Do something
        super(Child, self).my_method()
        # Do something more

import sys
original_module = sys.modules[__name__]  # 保存原模块对象的引用
sys.modules[__name__] = Child(__name__)
original_module.child_instance = sys.modules[__name__]  # 让原模块引用新的实例

这样原模块对象因为被original_module变量引用,不会被回收,模块中的Child和Parent类也会保留,super调用就能正常执行。

额外说明

如果你的项目可以升级到Python 3,使用无参数的super()会更简洁且不易出错,因为Python 3的super()会自动获取当前类和实例的信息,不需要显式传递参数:

class Parent:
    def my_method(self):
        print('Hello World')

class Child(Parent):
    def __init__(self, name):
        self.name = name
    def my_method(self):
        # Do something
        super().my_method()  # Python 3的无参数super
        # Do something more

import sys
sys.modules[__name__] = Child(__name__)

内容的提问来源于stack exchange,提问作者Vinayak Kaniyarakkal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:47:04