[轉]python3 跨目錄模塊調用,你真的懂了嗎?


小伙伴們,你們有遇到過調用自己寫的模塊(跨目錄模塊調用),提示你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())

 

運行結果

運行成功.png

到此,問題已經解決。

我們使用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
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM