小伙伴們,你們有遇到過調用自己寫的模塊(跨目錄模塊調用),提示你ImportError:No module named ...的情況,如果有,而且到現在還沒有搞明白的,我想說,你今天看對文章了。
這篇文章主要是講解怎么還原一個出錯的場景,然后分析出錯原因,一步一步的解決這個問題的思路。
項目結構
代碼內容
# model1/student.py def get_name(): return "hting"
# model1/new_student.py from student import get_name #注意這里的導入包的方式,會導致后面的異常 def get_student_name(): return get_name()
# model2/animal.py def get_name(): return "dog"
# model2/new_animal.py from model2.animal import get_name #注意這里的導入包的方式,和model1中new_student.py模塊中的導入方式有什么不一樣 def get_student_name(): return get_name()
注意上面腳本導入包的方式,和model1中new_student.py模塊中的導入方式有什么不一樣
# testModel/test.py 這里是運行入口 from model1 import student from model1 import new_student from model2 import animal from model2 import new_animal if __name__ == "__main__": print(student.get_name()) print(new_student.get_student_name()) print(animal.get_name()) print(new_animal.get_student_name())
執行代碼報錯
解釋出錯原因
查看剛才的報錯信息,我們可以知道,我們在執行test.py這個文件的時候,找不到student這個對象,那么我們找到包含“from student import get_name”的這個文件“new_student.py”,執行這個文件,沒有報錯,所以,這樣寫是絕對沒有問題的,那么為什么我們在外部對new_student.py這個模塊調用的時候會報錯?這里就要涉及到我們的python導包順序了。
(1)第一步:查找執行文件所在目錄
(2)第二步:查找執行文件所屬的項目目錄
(3)第三步:查找path環境配置的目錄
根據我的實驗,其實所謂的導包順序都是根據path中配置順序來的。我們做個實驗,在test.py中將path變量打印出來,結果如下
['C:\\HOMETing\\ForPython\\testforpath\\testModel', # 執行文件的所在目錄 'C:\\Python35\\lib\\site-packages\\django-2.0-py3.5.egg', 'C:\\Python35\\lib\\site-packages\\pytz-2017.2-py3.5.egg', 'C:\\HOMETing\\ForPython\\testforpath', # 執行文件所在項目的根目錄 'C:\\Python35\\python35.zip', 'C:\\Python35\\DLLs', 'C:\\Python35\\lib', 'C:\\Python35', 'C:\\Python35\\lib\\site-packages']
結合我們這個問題,會執行這樣的步驟
(1)查找執行文件的所在目錄,沒有student這個對象
(2)查找項目的根目錄下,沒有student這個對象
(3)查找path中的其他目錄也是沒有這個student對象的
(4)執行上面4個步驟之后都沒有找到這個對象,所以報錯
根據上面的分析,多少應該有了解決思路:就是將我們student所在的目錄加入到path變量中。
解決這個問題
根據上面步驟的分析,我們嘗試將model1這個包路徑加入到path變量中,看是否解決了問題。
在代碼中添加如下代碼
import sys sys.path.append("../model1")
test.py模塊修改之后的代碼
# test.py import sys sys.path.append("../model1") # print(sys.path) # 打印出path,調試使用 from model1 import student from model1 import new_student from model2 import animal from model2 import new_animal if __name__ == "__main__": print(student.get_name()) print(new_student.get_student_name()) print(animal.get_name()) print(new_animal.get_student_name())
運行結果
到此,問題已經解決。
我們使用print(sys.path)將path打印出來看一下
[
'C:\\HOMETing\\ForPython\\testforpath\\testModel', 'C:\\Python35\\lib\\site-packages\\django-2.0-py3.5.egg', 'C:\\Python35\\lib\\site-packages\\pytz-2017.2-py3.5.egg', 'C:\\HOMETing\\ForPython\\testforpath', 'C:\\Python35\\python35.zip', 'C:\\Python35\\DLLs', 'C:\\Python35\\lib', 'C:\\Python35', 'C:\\Python35\\lib\\site-packages', '../model1' # 新加入的path ]
另外:我建議不要使用將相對變量的路徑加入到path中,建議使用絕對變量。方法如下
import sys import os sys.path.append(os.path.abspath("../model1")) # os.path.abspath(path) # 返回path規范化的絕對路徑。
練習題
讀完這篇文章,我相信小伙伴們肯定是有收獲的,那么我們嘗試着做一個簡單的題來鞏固一下。
為什么new_student.py中的導包方式不會引發異常呢?
作者:亭子青年
鏈接:https://www.jianshu.com/p/61ed747680e2
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。
