2021-01-27
首先我們需要了解一下基礎:
參考我的博客:https://www.cnblogs.com/zhangchao0515/p/14333370.html
接下來,我們講的重點是 Python 模塊(Module)調用
一、我們先創建一個測試項目python-module
1、搜索路徑
當你導入一個模塊,Python 解析器對模塊位置的搜索順序是:
- 1、當前目錄
- 2、如果不在當前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每個目錄。
- 3、如果都找不到,Python會察看默認路徑。UNIX下,默認路徑一般為/usr/local/lib/python/。
模塊搜索路徑存儲在 system 模塊的 sys.path 變量中。變量里包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄。
2、Python中的包
包是一個分層次的文件目錄結構,它定義了一個由模塊及子包,和子包下的子包等組成的 Python 的應用環境。
簡單來說,包就是文件夾,但該文件夾下必須存在 __init__.py 文件, 該文件的內容可以為空。__init__.py 用於標識當前文件夾是一個包。
3、目錄結構如下
目錄是D:\Projects\python\vscode\python-module
python-module src main package1 __init__.py module1.py package2 package3 __init__.py module2.py __init__.py module2.py moduletest1.py moduletest2.py moduletest3.py moduletest4.py test

4、文件說明
def fun1(): print ("我是來自 module1")
module2.py 如下所示:
def fun2(): print ("我是來自 module2")
module3.py 如下所示:
def fun3(): print ("我是來自 module3")
5、執行方法
1)打開cmd
2)切換到要執行的py目錄下
3)執行py
例如:
python moduletest1.py
一、python默認的模塊導入執行過程
我們知道了搜索路徑,我們直接考慮第一種搜索:
當你導入一個模塊,Python 解析器對模塊位置的搜索順序是:
- 1、當前目錄
- 2、如果不在當前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每個目錄。
- 3、如果都找不到,Python會察看默認路徑。UNIX下,默認路徑一般為/usr/local/lib/python/。
模塊搜索路徑存儲在 system 模塊的 sys.path 變量中。變量里包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄。
會先搜索當前目錄,其實就是把當前目錄臨時添加到環境變量,作用域僅限於該py文件。由此引入了方法1
1. python默認的模塊導入執行過程-- 1) 要么是同一目錄下,可以相互調用 2) 要么是在子目錄下,可以從當前模塊往下 (都是需要__init__.py,而且是根據python自己的機制) 針對1)和2)是默認的機制-- python會自動將該文件的的路徑臨時添加到環境變量中,類似在文件中 sys.path.append('當前py文件目錄')
1、首先我們先打印一下 sys.path看一下環境
moduletest1.py如下
import sys # 測試第一種:使用python默認的模塊導入機制 # 只能導入同一目錄或子目錄下的模塊,效果類似 sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 # python moduletest1.py -- 作用域只是當前的python if __name__ == '__main__': print(sys.path)
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
我們可以看到,默認就會把該目錄添加到環境變量中。
2、我們直接引入模塊module2.py和module3.py
moduletest1.py如下
import sys # 測試第一種:使用python默認的模塊導入機制 # 只能導入同一目錄或子目錄下的模塊,效果類似 sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 # python moduletest1.py -- 作用域只是當前的python # 1. 這個是在同一目錄下,可以相互調用。效果類似在該文件中添加 sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 from module2 import fun2 # 2. 這個是在子目錄下,只能自己調用子目錄的,反過來不行。效果類似在該文件中添加 sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 from package3.module3 import fun3 # 3. 會報錯,不識別模塊package1 # from package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() # fun1()
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:

這是因為:搜索路徑,會先搜索當前目錄
3、我們再引入模塊module1.py
import sys # 測試第一種:使用python默認的模塊導入機制 # 只能導入同一目錄或子目錄下的模塊,效果類似 sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 # python moduletest1.py -- 作用域只是當前的python # 1. 這個是在同一目錄下,可以相互調用。效果類似在該文件中添加 sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 from module2 import fun2 # 2. 這個是在子目錄下,只能自己調用子目錄的,反過來不行。效果類似在該文件中添加 sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 from package3.module3 import fun3 # 3. 會報錯,不識別模塊package1 from package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() fun1()
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:

那是因為他不會往上級目錄搜索
二、通過sys.path.append 或者sys.path.exclude臨時導入環境變量
當你導入一個模塊,Python 解析器對模塊位置的搜索順序是:
- 1、當前目錄
- 2、如果不在當前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每個目錄。
- 3、如果都找不到,Python會察看默認路徑。UNIX下,默認路徑一般為/usr/local/lib/python/。
模塊搜索路徑存儲在 system 模塊的 sys.path 變量中。變量里包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄。
通過sys.path.append 或者sys.path.exclude臨時導入環境變量,它的作用域也只是該py文件。
1、按照慣例先看一下sys.path
moduletest2.py如下
import sys
# 測試第二種:
# 在文件中添加 sys.path.append('項目根目錄'), sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件
# python moduletest2.py -- 作用域只是當前的python
if __name__ == '__main__': print(sys.path)
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
2、我們直接引入模塊module1.py和module2.py和module3.py
moduletest2.py如下
import sys import os # 測試第二種: # 在文件中添加 sys.path.append('項目根目錄'), sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 # python moduletest2.py -- 作用域只是當前的python # 獲取當前文件的目錄 # curpath = os.path.abspath(os.path.dirname(__file__)) # 獲取項目根目錄 D:\\Projects\\python\\vscode\\python-module projectpath = os.path.abspath(os.path.dirname(__file__)+r'../../../') # 1. 在該文件中添加 sys.path.append('項目根目錄') -- 作用域只是當前py文件 sys.path.append(projectpath) from src.main.package2.module2 import fun2 # 2. 在該文件中添加 sys.path.append('當前文件所在的目錄') ,python默認會把該目錄加入,不需要這步操作 -- 作用域只是當前py文件 # sys.path.append(curpath) # from module2 import fun2 from src.main.package2.package3.module3 import fun3 from src.main.package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() fun1()
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
所以,環境變量里面一個是自動添加的目錄,一個是我們自己添加的目錄,兩個同樣的作用域是該py文件。且都是臨時的。
自動添加的:'D:\\Projects\\python\\vscode\\python-module\\src\\main\\package2' 我們添加的:'D:\\Projects\\python\\vscode\\python-module'
由此我們可以添加'D:\\Projects\\python\\vscode\\python-module'目錄下的模塊,需要引入相關包。該方法不能動源碼結構,否則要大量修改源碼。
當然我們的包名引入還可以用一的,因為也存在 'D:\\Projects\\python\\vscode\\python-module\\src\\main\\package2'。
3、混用這兩個路徑
moduletest2_1.py如下
import sys import os # 測試第二種: # 在文件中添加 sys.path.append('項目根目錄'), sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 # python moduletest2_1.py -- 作用域只是當前的python # 獲取當前文件的目錄 # curpath = os.path.abspath(os.path.dirname(__file__)) # 獲取項目根目錄 D:\\Projects\\python\\vscode\\python-module projectpath = os.path.abspath(os.path.dirname(__file__)+r'../../../') # 1. 在該文件中添加 sys.path.append('項目根目錄') -- 作用域只是當前py文件 sys.path.append(projectpath) # 很明顯用這個路徑'D:\\Projects\\python\\vscode\\python-module\\src\\main\\package2' from module2 import fun2 from package3.module3 import fun3 # 很明顯用這個路徑 D:\\Projects\\python\\vscode\\python-module from src.main.package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() fun1()
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
真會玩!!!
4、我們再引入模塊module1.py和module2.py和module3.py
moduletest2_2.py如下
import sys import os # 測試第二種: # 在文件中添加 sys.path.append('項目根目錄'), sys.path.append('當前文件所在的目錄') -- 作用域只是當前py文件 # python moduletest2_2.py -- 作用域只是當前的python # 獲取當前文件的目錄 # curpath = os.path.abspath(os.path.dirname(__file__)) # 獲取項目的main目錄 D:\\Projects\\python\\vscode\\python-module\\src\\main mainpath = os.path.abspath(os.path.dirname(__file__)+r'../') # 1. 在該文件中添加 sys.path.append('項目根main目錄') -- 作用域只是當前py文件 sys.path.append(mainpath) from package2.module2 import fun2 from package2.package3.module3 import fun3 from package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() fun1()
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
是不是類似java的包,好會玩,快被玩壞了!!!
三、在命令窗口設置 PYTHONPATH
當你導入一個模塊,Python 解析器對模塊位置的搜索順序是:
- 1、當前目錄
- 2、如果不在當前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每個目錄。
- 3、如果都找不到,Python會察看默認路徑。UNIX下,默認路徑一般為/usr/local/lib/python/。
模塊搜索路徑存儲在 system 模塊的 sys.path 變量中。變量里包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄。
這里我們就用到第2種搜索
1、按照慣例,先看一下sys.path
moduletest3.py如下
import sys if __name__ == '__main__': print(sys.path)
打開cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
2、在命令行設置PYTHONPATH -- 作用域是該窗口,只要窗口不關閉,在窗口中執行就行
moduletest3.py如下
import sys
if __name__ == '__main__': print(sys.path)
打開cmd,執行
set PYTHONPATH=D:\Projects\python\vscode\python-module
echo %PYTHONPATH%
結果如下所示:
切換到該文件所在目錄,再次執行
python moduletest1.py
結果如下所示:
在該環境變量中:
自動添加的:'D:\\Projects\\python\\vscode\\python-module\\src\\main\\package2'
我們添加的:'D:\\Projects\\python\\vscode\\python-module'
由此我們可以添加'D:\\Projects\\python\\vscode\\python-module'目錄下的模塊,需要引入相關包。
這里的作用域是該窗口。
3、引入模塊module1.py和module2.py和module3.py
moduletest3.py如下
import sys # 測試第三種:在cmd中切換到該目錄下,執行 set PYTHONPATH=D:\\Projects\\python\\vscode\\python-module # 我們可以查看 echo %PYTHONPATH% # 作用域是該cmd窗口,這要窗口下執行,都是有該環境變量存在 # python moduletest3.py from src.main.package2.module2 import fun2 from src.main.package2.package3.module3 import fun3 from src.main.package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() fun1()
在剛才窗口中執行
python moduletest1.py
結果如下所示:
如果窗口沒有設置 PYTHONPATH,肯定會報錯。
什么?你不信!!!
那我們就測試一下
重新打開一個窗口或者在該窗口執行以下操作:
set PYTHONPATH=
結果如下:
在剛才窗口中執行
python moduletest1.py
結果如下所示:
我就說嘛,請不要抬杠!!!
4、如果是在pycharm中,則不會報錯,不需要在命令行設置PYTHONPATH,因為pycharm已經設置好了
注意!!!好玩的又來了。
有些會問,我沒有設置PYTHONPATH,為什么在pycharm沒有報錯,那是因為pycharm已經設置好了。
pycharm就是采用類似這種的策略。
1)我們打開pycharm,導入該項目,看一下
打開 File --> Settings --> Build,Execution,Deployment --> Console --> Python Console
我們看一下啟動腳本 Starting script
import sys; print('Python %s on %s' % (sys.version, sys.platform)) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])
好家伙!!!
啟動腳本肯定是先執行的。 -- 至於如何設計,不太清楚,你們研究好了可以告訴我一聲,我謝謝啊。
(1) 這里面先引入 import sys;
(2) 之后調用print('Python %s on %s' % (sys.version, sys.platform))打印信息,
我的打印結果是
也就是說
sys.version: 3.8.3 (default, Jul 2 2020, 17:30:36) [MSC v.1916 64 bit (AMD64)]
sys.platform: win32
(3) 然后是 sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]),把目錄添加到環境變量中,
至於WORKING_DIR_AND_PYTHON_PATHS是識別不了的,pycharm肯定在其他地方定義了。
不過幸虧這名字取得我們能看懂意思,就是就是工作目錄和python目錄。
這里的工作目錄一看就是項目目錄。我們可以驗證一下。
2)我們已經把項目導入了pycharm,我們執行 moduletest3.py 試試看
當然我們這里什么都沒設置
moduletest3.py如下:-- 和之前一樣
import sys # 測試第三種:在cmd中切換到該目錄下,執行 set PYTHONPATH=D:\\Projects\\python\\vscode\\python-module # 我們可以查看 echo %PYTHONPATH% # 作用域是該cmd窗口,這要窗口下執行,都是有該環境變量存在 # python moduletest3.py from src.main.package2.module2 import fun2 from src.main.package2.package3.module3 import fun3 from src.main.package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() fun1()
我們直接點pycharm的執行
結果如下:
我們把結果的內容復制下來:
D:\ProgramFiles\Anaconda3\python.exe D:/Projects/python/vscode/python-module/src/main/package2/moduletest3.py ['D:\\Projects\\python\\vscode\\python-module\\src\\main\\package2', 'D:\\Projects\\python\\vscode\\python-module', 'D:\\ProgramFiles\\JetBrains\\PyCharm 2020.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\ProgramFiles\\Anaconda3\\python38.zip', 'D:\\ProgramFiles\\Anaconda3\\DLLs', 'D:\\ProgramFiles\\Anaconda3\\lib', 'D:\\ProgramFiles\\Anaconda3', 'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages', 'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\win32', 'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\win32\\lib', 'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\Pythonwin', 'D:\\ProgramFiles\\JetBrains\\PyCharm 2020.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend'] 我是來自 module2 我是來自 module3 我是來自 module1 Process finished with exit code 0
我的天,sys.path 中包含
'D:\\Projects\\python\\vscode\\python-module\\src\\main\\package2', 'D:\\Projects\\python\\vscode\\python-module'
所以嘛,不要抬杠!!!
四、設置全局變量 -- 作用域是一直存在
1、添加環境變量

2、按照慣例,我們測試一下sys.path
moduletest4.py如下
import sys # 測試第四種:設置全局變量 -- 作用域是一直存在 # 對於Windows,右鍵我的電腦 --> 屬性 --> 高級系統設置 --> 環境變量 --> 既可以添加用戶環境變量,也可以添加系統環境變量 --> # 新建 --> 添加變量名:PYTHONPATH,添加變量值:D:\Projects\python\vscode\python-module --> 確定 # python moduletest4.py if __name__ == '__main__': print(sys.path)
打開新的cmd(老的還是老配置,只有新的),切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
sys.path 中包含
'D:\\Projects\\python\\vscode\\python-module\\src\\main\\package2',
'D:\\Projects\\python\\vscode\\python-module'
3、我們直接引入模塊module1.py和module2.py和module3.py
moduletest4.py如下
import sys # 測試第四種:設置全局變量 -- 作用域是一直存在 # 對於Windows,右鍵我的電腦 --> 屬性 --> 高級系統設置 --> 環境變量 --> 既可以添加用戶環境變量,也可以添加系統環境變量 --> # 新建 --> 添加變量名:PYTHONPATH,添加變量值:D:\Projects\python\vscode\python-module --> 確定 # python moduletest4.py from src.main.package2.module2 import fun2 from src.main.package2.package3.module3 import fun3 from src.main.package1.module1 import fun1 if __name__ == '__main__': print(sys.path) fun2() fun3() fun1()
打開新的cmd,切換到該文件所在目錄,執行
python moduletest1.py
結果如下所示:
五、把文件添加到默認路徑中 -- 還是算了吧,一般都不用這種的。
除非是針對python的封裝等,比如Anaconda等。請自行解決。
當你導入一個模塊,Python 解析器對模塊位置的搜索順序是:
- 1、當前目錄
- 2、如果不在當前目錄,Python 則搜索在 shell 變量 PYTHONPATH 下的每個目錄。
- 3、如果都找不到,Python會察看默認路徑。UNIX下,默認路徑一般為/usr/local/lib/python/。
模塊搜索路徑存儲在 system 模塊的 sys.path 變量中。變量里包含當前目錄,PYTHONPATH和由安裝過程決定的默認目錄。
總結:
1、按照自動搜索方法,會先搜索當前目錄,但是該方法的缺點是不能識別上級目錄的模塊,並且作用域只是該py文件
2、自己在py中添加環境變量,會識別本目錄,以及從添加目錄開始的模塊,但是該方法的缺點是每個py文件都要添加環境變量,並且作用域只是該py文件
3、打開cmd,設置本窗口的變量。 set PYTHONPATH=D:\\Projects\\python\\vscode\\python-module,可以通過 echo %PYTHONPATH% 查看。這么設置的話,作用域是本窗口。
4、設置全局的環境變量。作用域一直存在。我們不需要了在刪除之。
5、把文件添加到默認路徑中。
參考:Python 模塊 - https://www.runoob.com/python/python-modules.html