python中遇到循环import即circular import的问题原理剖析及解决方案
在python中常常會遇到循環import即circular import的問題,今天主要給大家介紹了關于Python中循環引用(import)失敗的解決方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒。
一、前言
最近在開發智能家居項目項目中,由于代碼結構層級劃分不合理,導致了循環引用(import)module失敗的問題,錯誤如下:
? File "./design_app/views.py", line 7, in <module>
? ? import alg.auto_design.evaluate as evaluate
? File "./alg/auto_design/evaluate.py", line 5, in <module>
? ? from alg.auto_design.helpers.json_io import json2fp
? File "./alg/auto_design/helpers/__init__.py", line 2, in <module>
? ? from alg.auto_design.helpers import json_io
? File "./alg/auto_design/helpers/json_io.py", line 14, in <module>
? ? from alg.auto_design.room_type.dingroom.base import DiningRoom
? File "./alg/auto_design/room_type/dingroom/base.py", line 13, in <module>
? ? from alg.auto_design_easyhome.utility import get_opposite_bounds
? File "./alg/auto_design_easyhome/utility.py", line 8, in <module>
? ? from alg.auto_design_easyhome.room_type.master_bedroom import \
? File "./alg/auto_design_easyhome/room_type/master_bedroom/__init__.py", line 3, in <module>
? ? from alg.auto_design_easyhome.room_type.master_bedroom.base import MainBedroom
? File "./alg/auto_design_easyhome/room_type/master_bedroom/base.py", line 6, in <module>
? ? from alg.auto_design_easyhome.helpers import extract_rec
? File "./alg/auto_design_easyhome/helpers/__init__.py", line 2, in <module>
? ? from alg.auto_design_easyhome.helpers import json_io
? File "./alg/auto_design_easyhome/helpers/json_io.py", line 14, in <module>
? ? from alg.auto_design_easyhome.room_type.dingroom.base import DiningRoom
? File "./alg/auto_design_easyhome/room_type/dingroom/base.py", line 13, in <module>
? ? from alg.auto_design_easyhome.utility import get_opposite_bounds
ImportError: cannot import name 'get_opposite_bounds' from partially initialized module 'alg.auto_design_easyhome.utility' (most likely due to a circular import) (./alg/auto_design_easyhome/utility.py)
二、import執行過程
當我們import一個文件時,python會首先去查找這個文件之前是否被import過,如果這個文件之前有被import過,就不會重新再import一次。所以如果A模塊
代碼里import了B模塊,并且B模塊里又import了A模塊,python的執行順序會變成這樣:
- 開始執行模塊A
- 當A執行到import B的地方,則停止執行A模塊后面的代碼,轉而開始執行B模塊的代碼
- 當B模塊從頭執行到import A的地方時,python此時并不會回過頭去接著執行A剩余的代碼,而且將A模塊在中斷前已經初始化的屬性全加載到B模塊中
三、原理
這個時候就有一個問題,當前腳本Main第一次執行,需要執行from A import ,發現沒有A,就新建一個A在內存中,然后填充A模塊的信息,就會去執行A,此時,A里面要 from Main import D,那么因為Main已被執行,就直接從內存的map中取得Main的信息,不過此時Main的信息還沒有填充完,因為之前就是為了填充才轉到A的,這時從已有的空的Main中拿不到D,就會報錯,ImportError。
四、解決方案
1、方案一 合理劃分項目代碼層級
循環引用最大的本質問題是代碼層級結構劃分的不合理,所以最根本的、最合理的解決方案就是重新劃分好代碼的層級結構,使其合理化,自然就規避了循環引用的麻煩。
2、方案二 只引用當前的包,不引用具體的模塊
如果你的代碼是這樣,那么這種方式是會奏效的。
案例一:修改前
# a.pyfrom B import bdef a():pass# some codes# b.pyfrom A import adef b():a.a()#some codes案例一:修改后
# a.pyfrom B import bdef a():pass# some codes# b.pyimport Adef b():A.a.a()#some codes2、方案二 將引用放到函數內部
如果你的代碼是這樣,那么這種方式是會奏效的。
案例二:修改前
# a.pyfrom B import bdef a():pass# some codes# b.pyfrom A import adef b():a.a()#some codes案例二:修改后
# a.pyfrom B import bdef a():pass# some codes# b.pydef b():from A import aa.a()#some codes五、總結
只有理解了python在import時的工作原理,這種cicular import的問題才會很好的分析和解決。
總結
以上是生活随笔為你收集整理的python中遇到循环import即circular import的问题原理剖析及解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kaggle 房价预测竞赛优胜方案:用
- 下一篇: html-css练习题 (注册表单)