您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何理解Python模塊之間的相互引用問題”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何理解Python模塊之間的相互引用問題”吧!
在某次運行過程中出現了如下兩個報錯:
報錯1: ModuleNotFoundError: No module named '__main__.src_test1'; '__main__' is not a package 報錯2: ImportError: attempted relative import with no known parent package
于是基于這兩個報錯探究了一下python3中的模塊相互引用的問題,下面來逐個解析,請耐心看完。
好的,我們先來構造第一個錯,測試代碼結構如下:
|--- test_main.py |--- src |--- __init__.py |--- src_test1.py |--- src_test2.py
src_test2.py 代碼
class Test2(object): def foo(self): print('I am foo')
src_test1.py 代碼,引用Test2模塊
from .src_test2 import Test2 def fun1(): t2 = Test2() t2.foo() if __name__ == "__main__": fun1()
此時運行 src_test1.py 報錯“No module named '__main__.src_test1'; '__main__' is not a package”
主要在于引用src_test2模塊的時候,用的是相對路徑".",在import語法中翻譯成"./",也就是當前目錄下,按這樣理解也沒有問題,那為什么報錯呢?
從 PEP 328 中,我們找到了關于 the relative imports(相對引用)的介紹
通俗一點意思就是,你程序入口運行的那個模塊,就默認為主模塊,他的name就是‘main’,然后會將本模塊import中的點(.)替換成‘__main__’,那么 .src_test2就變成了 __main__.src_test2,所以當然找不到這個模塊了。
因此,建議的做法是在 src同層級目錄創建 引用模塊 test_main.py(為什么不在src目錄下創建,待會下一個報錯再講),并引用src_test1模塊,代碼如下:
from src.src_test1 import fun1 if __name__ == "__main__": fun1()
那為什么這樣執行就可以了呢,其中原理是什么呢?我是這樣理解的(歡迎糾正):test_main執行時,他被當做根目錄,因此他引用的src.src_test1 是絕對路徑,這樣引用到哪都不會錯,此時他的name=‘main’,當執行src_test1的時候,注意了此時test1的name是 src.src_test1,那么在test1中使用的是相對路徑,查找邏輯是先找到父節點(src目錄),再找父節點下面的src_test2,因此可以成功找到,Bingo!
構造一個例子,就可以理解上面的 執行目錄就是根目錄 的說法了,修改test1,使引用test_main:
from .. import test_main 報錯:ValueError: attempted relative import beyond top-level package
OK,那繼續構造第二個報錯:
上文中說過,解決main 的問題,就是創建一個模塊,來調用使用相對路徑的模塊,那么為什么我不能在相同目錄下創建這個文件來調用呢?讓我們來測試下代碼:
創建test_src.py文件,代碼結構變更如下:
|--- test_main.py |--- src |--- __init__.py |--- src_test1.py |--- src_test2.pys |--- test_src.py
test_src 代碼:
from src_test1 import fun1 if __name__ == "__main__": fun1()
執行報錯:ImportError: attempted relative import with no known parent package
當執行test_src時,按上文理解,此時執行文件所在的目錄為根目錄,那么引用test1的時候,需要注意的是,此時test1的name屬性不再是src.src_test1,因為程序感知不到src的存在,此時他的絕對路徑是 src_test1,此時再次引用相對路徑查找的test2,同樣的步驟,需要先找到父節點,而此時他自己就是根節點了,已經沒有父節點了,因此報錯“no known parent package”。
此時為了避免父節點產生矛盾,因此將test1中的引入去掉相對引用即可
from .src_test2 import Test2 --> from src_test2 import Test2
那使用相對路徑和絕對路徑,編譯器是怎么找到這個模塊的呢?
執行import的時候,存在一個引入的順序,即優先查找執行目錄下有沒有此文件,如沒有,再查找lib庫下,如還沒有,再查找sys.path中的路徑,如再沒有,報錯。
所以不管是當前目錄,還是 sys.path中的目錄,都可以查到 src_test2這個模塊,就可以編譯成功。
解決完上述問題后,不管我們用哪種方式,我們調試代碼時,都是單個文件調試,但此時根目錄就不對了,import方式又要改動,執行起來很麻煩,所以這里推薦另一種方式(有更好的方式歡迎留言),使用sys.path.append()的方法
import sys,os sys.path.append(os.getcwd()) from src.src_test2 import Test2
使用append的方式,將程序文件根目錄放進了sys.path中,然后再引用絕對路徑,這樣的方式,不管使用上文中的第一或第二執行方式都可以調用,也可以單獨編譯test1文件,不用修改import路徑,也是相對安全的方式。但是缺點就是,如果你修改了某一個包名,需要將所有引用地方都修改一下,工作量大,所以因地制宜。
感謝各位的閱讀,以上就是“如何理解Python模塊之間的相互引用問題”的內容了,經過本文的學習后,相信大家對如何理解Python模塊之間的相互引用問題這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。