Python开发RPG时调用rpgLocations.Tavern报部分初始化模块无属性错误
问题成因
该报错是循环导入导致的模块初始化不完全:
- 你在
main.py中导入了rpgLocations模块,同时rpgLocations.py顶部又导入了main模块,两个模块形成双向依赖 - Python导入模块时会先在缓存
sys.modules中查找对应模块,找不到就会先创建一个空的模块对象加入缓存,再执行模块内的代码完成初始化 - 首次运行时导入顺序刚好走完全量初始化,但后续运行时(尤其是未完全关闭进程、使用热重载/在交互式环境重复运行代码的场景下),
main导入rpgLocations时,rpgLocations刚创建空模块对象就反过来导入main,main此时直接调用缓存里还没初始化完的rpgLocations对象的Tavern()方法,自然找不到对应属性,就会触发该报错。
排查步骤
- 先注释掉
rpgLocations.py里的import main代码,直接运行项目,如果报错消失即可确定是循环导入导致的问题 - 完全关闭运行进程,删除项目下的
__pycache__文件夹后重新运行,排除旧缓存干扰
解决方案
按改造成本从低到高有3种可行方案:
方案1:延迟导入main
不需要改动整体结构,把rpgLocations.py里的import main从顶层移到Tavern函数内部即可,只有调用方法时才会导入,避免顶层导入形成循环:
# rpgLocations.py 删掉顶部的import main def Tavern(): import main # 改为函数内部延迟导入 main.clear() main.PlayerStatus.CurrentPlayerLocation = 'Tavern' print('What would you like to do?\n\n\n') while True: main.pInput = input('1. Trade\n2. View quests\n3. gamble\n4. Look around\n5. Idk,\n6. Leave\n\n>') if main.pInput == '1': print('test works') break elif main.pInput == '6': NavigationPanel()
方案2:调整导入顺序
在main.py中,先定义完所有rpgLocations要调用的对象(clear函数、PlayerStatus类、NavigationPanel函数等),再导入rpgLocations:
# main.py 先完成所有公共内容的定义 def clear(): # 原清屏逻辑 pass class PlayerStatus: CurrentPlayerLocation = '' def NavigationPanel(): # 原导航逻辑 pass pInput = '' # 所有公共内容定义完成后再导入rpgLocations import rpgLocations # 后续再调用rpgLocations.Tavern()
方案3:抽离公共模块彻底打破循环依赖
长期更推荐该方案,把两个模块共同依赖的公共对象抽离到单独的common.py中,两个模块都导入common调用对应内容,从根源上解决双向依赖问题:
# common.py 示例,存放所有公共变量、方法 def clear(): # 原main里的清屏逻辑 pass class PlayerStatus: CurrentPlayerLocation = '' pInput = '' def NavigationPanel(): # 原导航逻辑 pass
修改rpgLocations.py导入common即可:
import common def Tavern(): common.clear() common.PlayerStatus.CurrentPlayerLocation = 'Tavern' print('What would you like to do?\n\n\n') while True: common.pInput = input('1. Trade\n2. View quests\n3. gamble\n4. Look around\n5. Idk,\n6. Leave\n\n>') if common.pInput == '1': print('test works') break elif common.pInput == '6': common.NavigationPanel()
内容的提问来源于stack exchange,提问作者dubber
相关产品推荐
相关产品推荐

