這篇文章主要給大家介紹了python中模組尋找的原理與方式,文中通過範例程式碼介紹的非常詳細,對大家的學習或工作具有一定的參考學習價值,需要的朋友們下面跟著小編來一起學習學習吧。
前言
本文主要給大家介紹了關於python模組尋找的原理與方式,分享出來供大家參考學習,下面話不多說,來一起看看詳細的介紹:
基礎概念
module
模組, 一個 py 檔案或以其他檔案形式存在的可被匯入的就是一個模組
package
包,包含有 __init__ 檔案的檔案夾
relative path
相對路徑,相對於某個目錄的路徑
absolute path
絕對路徑,全路徑
路徑尋找
python 解譯器尋找被引入的包或模組
Python 解譯器是如何尋找包和模組的
Python 執行一個 py 檔案,無論執行的方式是用絕對路徑還是相對路徑,interpreter 都會把檔案所在的 directory 加入 sys.path 這個 list 中,Python 就是在 sys.path 中尋找包和模組的,sys.path 中的內容本身又是又 Python 的環境變數決定。
code-1
#test.pyimport osimport sysprint sys.path[0]# executepython test.pypython /Users/x/workspace/blog-code/p2016_05_28_python_path_find/test.py
執行表明相對路徑和絕對路徑都輸出相同的結果,而且無論哪種執行方式,test.py 所在的檔案夾都會被加入 sys.path 的首位,也就是索引為0的位置。
Python 解譯器尋找包的順序是什麼
解譯器尋找包,首先搜尋 built-in module,其次搜尋 sys.path ,這樣的尋找順序將會導致同名包或模組被遮蔽。
code-2
#ls├── os.py├── test2.py├── redis.py#test2.pyimport osfrom redis import Redis#execute test2.pyTraceback (most recent call last): File "/Users/x/workspace/blog-code/p2016_05_28_python_path_find/test2.py", line 1, in <module> from redis import RedisImportError: cannot import name Redis
由於 os 是 built-in module,即使在同目錄下有同名模組,解譯器依然可以找到正確的 os 模組,可以證實 built-in module 不會被遮蔽,而 redis 屬於第三方模組,預設安裝位置是 Python 環境變數中的 site-packages,解譯器啟動之後會將此目錄中的內容加入 sys.path,由於目前的目錄會在 sys.path 的首位,目前的目錄的 redis 優先被找到,site-packages 中的 redis 模組被遮蔽了。
互動式執行環境的尋找順序
進入互動式執行環境,解譯器會自動把目前的目錄加入 sys.path, 這時目前的目錄是以相對路徑的形式出現在 sys.path 中:
>>> import os.path>>> import sys>>> os.path.abspath(sys.path[0])'/Users/x/workspace/blog-code'>>>
除此之外,其他與執行一個檔案是相同的。
模組中的 __file__ 變數
__file__ is the pathname of the file from which the module was loaded, if it was loaded from a file. 如果一個模組是從檔案載入的,__file__ 就是該模組的路徑名–Python Doc:
顧名思義,當模組以檔案的形式出現 __file__ 指的是模組檔案的路徑名,以相對路徑執行 __file__ 是相對路徑,以絕對路徑執行 __file__ 是絕對路徑。
#test3.pyprint __file__#相對路徑執行python test3.pytest3.py#絕對路徑執行python /Users/x/workspace/blog-code/p2016_05_28_python_path_find/test3.py/Users/x/workspace/blog-code/p2016_05_28_python_path_find/test3.py
為了保證__file__ 每次都能準確得到模組的正確位置,最好對其再取一次絕對路徑 os.path.abspath(__file__) 。
互動式 shell 中的 __file__
>>> __file__Traceback (most recent call last): File "<input>", line 1, in <module>NameError: name '__file__' is not defined
這是因為當前互動式shell的執行並不是以檔案的形式載入,所以不存在__file__ 這樣的屬性。
sys.argv[0] 變數
sys.argv[0] 是它用來擷取主入口執行檔案。
#test.pyimport sysprint __file__print sys.argv[0]
以上 print 輸出相同的結果,因為主執行檔案和__file__所屬的模組是同一個,當我們改變入口檔案,區別就出現了。
#test.pyimport sysprint __file__print sys.argv[0]#test2.pyimport test#execute test2.py/Users/x/workspace/blog-code/p2016_05_28_python_path_find/child/test.py #__file__test2.py #sys.argv[0]
總的來說,sys.argv[0] 是獲得入口執行檔案路徑,__file__ 是獲得任意模組檔案的路徑。
sys.modules 的作用
既然 Python 是在 sys.path 中搜尋模組的,那載入的模組存放在何處?答案就是 sys.modules。模組一經載入,Python 會把這個模組加入 sys.modules 中供下次載入使用,這樣可以加速模組的引入,起到緩衝的作用。
>>> import sys>>> sys.modules['tornado']Traceback (most recent call last): File "<input>", line 1, in <module>KeyError: 'tornado'>>> import tornado>>> sys.modules['tornado']<module 'tornado' from '/Users/x/python_dev/lib/python2.7/site-packages/tornado/__init__.pyc'>
前面說過 Python 解譯器啟動之後,會把預先載入 built-in module,可以通過 sys.modules 驗證。
>>> sys.modules['os']<module 'os' from '/Users/x/python_dev/lib/python2.7/os.pyc'>>>>
藉助 sys.modules 和 __file__,可以動態擷取所有已載入模組目錄和路徑。
>>> import os>>> os.path.realpath(sys.modules['os'].__file__)'/Users/x/python_dev/lib/python2.7/os.pyc'>>> import tornado>>> os.path.realpath(sys.modules['tornado'].__file__)'/Users/x/python_dev/lib/python2.7/site-packages/tornado/__init__.pyc'
def get_module_dir(name): path = getattr(sys.modules[name], '__file__', None) if not path raise AttributeError('module %s has not attribute __file__'%name) return os.path.dirname(os.path.abspath(path))
summary
總的來說,Python 是通過尋找 sys.path 來決定包的匯入,並且系統包優先順序>同目錄>sys.path,Python 中的特有屬性 __file__ 以及 sys.argv[0] ,sys.modules 都能協助我們理解包的尋找和匯入概念,只要能正確理解 sys.path 的作用和行為,理解包的尋找就不是難題了。