Python提示 TypeError: super(type, obj): obj must be an instance or subtype of type问题
在工作中有一天将debug下正常工作的python代码编译之后运行却抛出异常,提示“TypeError: super(type, obj): obj must be an instance or subtype of type”,引起这个问题的原因是因为type和obj类型不一致造成的(即obj对象不是由type类型的类创建的),但是debug下是工作的啊,突然想到会不会是由于编译后使用了pyd模块,模块加载时出现了问题。
为了找到错误的原因,构建了测试代码复线了错误过程,重复导入模块,对于pyd模块在使用api load_module时必须使用该模块的名称导入,否则会导入失败,但是有时必须要修改名称,因为在不同的目录下或许会有相同名称但功能不同的模块,如果不修改名称后面导入的模块会覆盖之前导入的模块,见图1.1 测试代码。
现在的问题是修改了名称,但是现在发现可能还是存在覆盖导入的问题,在第二次导入后会使第一次成功创建的对象在方法内调用super()时抛出“TypeError: super(type, obj): obj must be an instance or subtype of type”异常,见图1.1 测试代码。
图1.1 测试代码
1. 可能是因为在导入“a”后触发的(因为名称一样都是a)reload操作修改了a模块对象,由于存在引用(可能有部分不可见的数据结构),同时也影响了‘a1’模块对象内部的部分数据?从而导致奇怪的异常。
2. 能是因为在导入“a”后触发的(因为名称一样都是a)reload操作修改了a模块对象导致pyhton 解释器在解释的时候将a和a1模块都一律按照reload后的模块来解释。
简单验证上面的说法,在项目的根目录下新建名为a、b的文件夹,分别放置a.pyd模块,模块内的测试代码见图2.1,这段程序执行到16行的时候错误,错误提示当前对象的类型与类的类型不一致(说明当前对象不是这个类的实例),当然这个错误是出现在重复导入a模块之后,在这之前调用get方法并没有出现异常,见图2.2。
图2.1 a.pyd模块源文件
图2.2 测试代码1
下面这个测试是分别通过a1_module.B类创建b_obj对象,re_a_module.B类创建re_b_obj对象,通过内部打印id,显示它们的id是一致的,都是76028552,即为re_a_module.B类的id,表明python解释器在内部解释时,将之前第一次导入的类也解释成后面重载的类,导致了实例化调用super时抛出TypeError。综上所述,假设2成立,见图2.3。
图2.3 测试代码2
经过分析,我认为只要不引起模块的reload就能够避免该问题,故在第一次导入模块后从系统模块字典中pop出‘a’模块,导出的模块以‘a1’为键更新到sys.modules中,就能够解决上述问题。例:sys.modules.update({'a1': sys.modules.pop('a')});见图3.1。
图3.1 模拟案例解决方案