Python实例化类型交叉引用的类报引用错误如何解决
问题原因
这是典型的类型注解前向引用场景:Python解析类下函数的类型注解时,会立刻查找注解里的类对象,不管怎么调整Foo和Bar的定义顺序,总有一个类在被解析时,另一个类还没完成创建,自然会抛出名称错误。把两个类拆分到不同文件不仅解决不了依赖问题,还会触发循环导入报错,完全没必要这么做。
解决方案
方案1:开启延迟注解求值(推荐,适配Python 3.7及以上版本)
在文件最开头加入from __future__ import annotations即可。这个导入会让当前文件内所有类型注解延迟到整个模块所有代码加载完成后再解析,你原来的业务代码不需要做任何修改,直接就能正常运行,mypy、Pyright这类静态类型检查工具也能正常识别类型关系,是目前处理这类互相引用场景的最优解。
注意:future导入必须放在文件所有业务代码的最前面,否则会触发语法错误。
修改后的完整代码:
from __future__ import annotations class Foo: def some_func(self, x: Bar): pass # 执行业务逻辑 class Bar: def some_other_func(self, x: Foo): pass # 执行业务逻辑
方案2:字符串形式前向引用(全Python版本兼容)
如果你的运行环境低于Python 3.7,无法使用上述future导入,可以把定义阶段还不存在的类名用引号包裹成字符串,Python解析注解时遇到字符串形式的类型会自动延后匹配,不需要调整类的依赖关系。
示例代码:
class Foo: # Bar此时还未定义,用字符串包裹类名即可 def some_func(self, x: 'Bar'): pass # 执行业务逻辑 class Bar: # Foo已经完成定义,可以直接引用 def some_other_func(self, x: Foo): pass # 执行业务逻辑
如果调换两个类的定义顺序,只需要对应把还未定义的那个类名加上引号就行。缺点是如果互相引用的位置较多,手动加引号会有一定维护成本。
内容的提问来源于stack exchange,提问作者ExodusSolis
相关产品推荐
相关产品推荐

