[[toc]]
前言
在學(xué)習(xí)unittest框架時(shí)發(fā)現(xiàn),在IDE(pycharm)上可以正常運(yùn)行腳本,但在CMD中運(yùn)行腳本時(shí),出現(xiàn)了錯誤,無法運(yùn)行,提示“引包錯誤”。通過查找資料,找到了答案,現(xiàn)在總結(jié)一下:獲取絕對路徑,python引包機(jī)制
一、在pycharm運(yùn)行正常,在命令行窗口出現(xiàn)引包錯誤,怎么辦?
在出現(xiàn)錯誤的那個(gè)py文件,找到需要引入的包錯誤的工程路徑,然后sys.path.insert(相應(yīng)的路徑),如:

我在2包中調(diào)用1包中的first.py里面的函數(shù)hello(),在 pycharm運(yùn)行正常,但是在命令行運(yùn)行出錯
Traceback(most recent call last):
??File "second.py", line8, in <module>
??????from first import hello
ModuleNotFoundError: No module named 'first'
這時(shí)候只需要在second.py文件上,在最上面添加這個(gè)代碼:
import os
import sys
dir_mytest = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, dir_mytest)
from first import hello
這里為什么要這么做呢?是因?yàn)橐话鉏DE都會自動的匹配好相關(guān)的環(huán)境路徑,故在IDE中運(yùn)行沒問題。但在cmd命令行中就會出現(xiàn)“引包錯誤”的問題,故在腳本中,我們通常都要把絕對路徑插入到os.path中。
有點(diǎn)要注意的是:python3是向下機(jī)制的。所以插入路徑的代碼要放在引包代碼之前
二、python 獲取當(dāng)前絕對路徑
在使用python的時(shí)候總會遇到路徑切換的使用情況,如想從文件夾test下的test.py調(diào)用data文件夾下的data.txt文件:
.
└── folder
├── data
│ └── data.txt
└── test
└── test.py
一種方法可以在data文件下加入init.py 然后在test.py 中import data 就可以調(diào)用data.txt文件;
另一種方法可以獲取絕對路徑加入到os.path中
而獲取絕對路徑的方法有多種:
方法一
import os
# 獲取當(dāng)前目錄絕對路徑
dir_path = os.path.dirname(os.path.abspath(__file__))
print('當(dāng)前目錄絕對路徑:', dir_path)
# 獲取上級目錄絕對路徑
dir_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print('上級目錄絕對路徑:', dir_path)
運(yùn)行結(jié)果:
當(dāng)前目錄絕對路徑: D:\mytest\mytest\abspath
上級目錄絕對路徑: D:\mytest\mytest
方法二
import os
import sys
dir_path = os.path.abspath(os.path.split(__file__)[0])
print('當(dāng)前目錄絕對路徑:', dir_path)
# 獲取上級目錄絕對路徑
dir_path = os.path.abspath(os.path.split(os.path.split(__file__)[0])[0])
print('上級目錄絕對路徑:', dir_path)
運(yùn)行結(jié)果:
當(dāng)前目錄絕對路徑: D:\mytest\mytest\abspath
上級目錄絕對路徑: D:\mytest\mytest
方法三
import os
print('***獲取當(dāng)前目錄***')
print(os.getcwd())
print('***獲取上級目錄***')
print(os.path.abspath(os.path.join(os.getcwd(), "..")))
print('***獲取上上級目錄***')
print(os.path.abspath(os.path.join(os.getcwd(), "../..")))
運(yùn)行結(jié)果:
***獲取當(dāng)前目錄***
D:\mytest\mytest\abspath
***獲取上級目錄***
D:\mytest\mytest
***獲取上上級目錄*** __粗體__
D:\mytest
三、python 引包機(jī)制
python中,每個(gè)py文件被稱之為模塊,每個(gè)具有_init_.py文件的目錄被稱為包。只要模塊或者包所在的目錄在sys.path中,就可以使用import 模塊或import 包來使用。
如果想使用非當(dāng)前模塊中的代碼,需要使用Import,這個(gè)大家都知道。
如果你要使用的模塊(py文件)和當(dāng)前模塊在同一目錄,只要import相應(yīng)的文件名就好,比如在a.py中使用b.py:
import b
但是如果要import一個(gè)不同目錄的文件(例如b.py)該怎么做呢?
首先需要使用sys.path.insert()方法將b.py所在目錄加入到搜素目錄中。然后進(jìn)行import即可。
python在執(zhí)行import語句時(shí),到底進(jìn)行了什么操作,按照python的文檔,它執(zhí)行了如下操作:
第1步,創(chuàng)建一個(gè)新的,空的module對象(它可能包含多個(gè)module);
第2步,把這個(gè)module對象插入sys.module中
第3步,裝載module的代碼(如果需要,首先必須編譯)
第4步,執(zhí)行新的module中對應(yīng)的代碼。
在執(zhí)行第3步時(shí),首先要找到module程序所在的位置,其原理為:
如 果需要導(dǎo)入的module的名字是m1,則解釋器必須找到m1.py,它首先在當(dāng)前目錄查找,然后是在環(huán)境變量PYTHONPATH中查找。 PYTHONPATH可以視為系統(tǒng)的PATH變量一類的東西,其中包含若干個(gè)目錄。如果PYTHONPATH沒有設(shè)定,或者找不到m1.py,則繼續(xù)搜索 與python的安裝設(shè)置相關(guān)的默認(rèn)路徑
事實(shí)上,搜索的順序是:
當(dāng)前路徑 (以及從當(dāng)前目錄指定的sys.path),然后是PYTHONPATH,然后是python的安裝設(shè)置相關(guān)的默認(rèn)路徑。正因?yàn)榇嬖谶@樣的順序,如果當(dāng)前 路徑或PYTHONPATH中存在與標(biāo)準(zhǔn)module同樣的module,則會覆蓋標(biāo)準(zhǔn)module。也就是說,如果當(dāng)前目錄下存在xml.py,那么執(zhí) 行import xml時(shí),導(dǎo)入的是當(dāng)前目錄下的module,而不是系統(tǒng)標(biāo)準(zhǔn)的xml。
包機(jī)制
a.py文件:
# a.py
def add_func(a,b):
return a+b
b.py文件:
# b.py
from a import add_func
print ("Result of 1 plus 2 is: ")
print (add_func(1,2))
模塊(module)可以定義在包里面。Python定義包的方式稍微有點(diǎn)古怪,假設(shè)我們有一個(gè)parent文件夾,該文件夾有一個(gè)child子文件夾。child中有一個(gè)模塊(module) a.py , 如何讓Python知道這個(gè)文件層次結(jié)構(gòu)?很簡單,每個(gè)目錄都放一個(gè)名為init.py 的文件,該文件內(nèi)容可以為空,這個(gè)層次結(jié)構(gòu)如下所示:
parent
--_init.py
--child
-- __init_.py
--a.py
那么Python如何找到我們定義的module?在標(biāo)準(zhǔn)包sys中,path屬性記錄了Python的包路徑。你可以將之打印出來:
import sys
print(sys.path)
通常我們可以將module的包路徑放到環(huán)境變量PYTHONPATH中,該環(huán)境變量會自動添加到sys.path屬性。另一種方便的方法是編程中直接指定我們的module路徑到sys.path 中:
import sys
import os
dir_mytest = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, dir_mytest)
from a import add_func
print (sys.path)
print ("Result of 1 plus 2 is: ")
print (add_func(1,2))