python中模塊查找的原理與方法詳解
前言
本文主要給大家介紹了關(guān)于python模塊查找的原理與方式,分享出來供大家參考學(xué)習(xí),下面話不多說,來一起看看詳細(xì)的介紹:
基礎(chǔ)概念
module
模塊, 一個(gè) py 文件或以其他文件形式存在的可被導(dǎo)入的就是一個(gè)模塊
package
包,包含有 __init__ 文件的文件夾
relative path
相對路徑,相對于某個(gè)目錄的路徑
absolute path
絕對路徑,全路徑
路徑查找
python 解釋器查找被引入的包或模塊
Python 解釋器是如何查找包和模塊的
Python 執(zhí)行一個(gè) py 文件,無論執(zhí)行的方式是用絕對路徑還是相對路徑,interpreter 都會(huì)把文件所在的 directory 加入 sys.path
這個(gè) list 中,Python 就是在 sys.path
中查找包和模塊的,sys.path
中的內(nèi)容本身又是又 Python 的環(huán)境變量決定。
code-1
#test.py import os import sys print sys.path[0] # execute python test.py python /Users/x/workspace/blog-code/p2016_05_28_python_path_find/test.py
執(zhí)行表明相對路徑和絕對路徑都輸出相同的結(jié)果,而且無論哪種執(zhí)行方式,test.py 所在的文件夾都會(huì)被加入 sys.path
的首位,也就是索引為0的位置。
Python 解釋器查找包的順序是什么
解釋器查找包,首先搜索 built-in module,其次搜索 sys.path
,這樣的查找順序?qū)?huì)導(dǎo)致同名包或模塊被遮蔽。
code-2
#ls ├── os.py ├── test2.py ├── redis.py #test2.py import os from redis import Redis #execute test2.py Traceback (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 Redis ImportError: cannot import name Redis
由于 os 是 built-in module,即使在同目錄下有同名模塊,解釋器依然可以找到正確的 os 模塊,可以證實(shí) built-in module 不會(huì)被遮蔽,而 redis 屬于第三方模塊,默認(rèn)安裝位置是 Python 環(huán)境變量中的 site-packages,解釋器啟動(dòng)之后會(huì)將此目錄中的內(nèi)容加入 sys.path
,由于當(dāng)前目錄會(huì)在 sys.path
的首位,當(dāng)前目錄的 redis 優(yōu)先被找到,site-packages 中的 redis 模塊被遮蔽了。
交互式執(zhí)行環(huán)境的查找順序
進(jìn)入交互式執(zhí)行環(huán)境,解釋器會(huì)自動(dòng)把當(dāng)前目錄加入 sys.path
, 這時(shí)當(dāng)前目錄是以相對路徑的形式出現(xiàn)在 sys.path
中:
>>> import os.path >>> import sys >>> os.path.abspath(sys.path[0]) '/Users/x/workspace/blog-code' >>>
除此之外,其他與執(zhí)行一個(gè)文件是相同的。
模塊中的 __file__ 變量
__file__ is the pathname of the file from which the module was loaded, if it was loaded from a file. 如果一個(gè)模塊是從文件加載的,__file__ 就是該模塊的路徑名–Python Doc:
顧名思義,當(dāng)模塊以文件的形式出現(xiàn) __file__ 指的是模塊文件的路徑名,以相對路徑執(zhí)行 __file__ 是相對路徑,以絕對路徑執(zhí)行 __file__ 是絕對路徑。
#test3.py print __file__ #相對路徑執(zhí)行 python test3.py test3.py #絕對路徑執(zhí)行 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__ 每次都能準(zhǔn)確得到模塊的正確位置,最好對其再取一次絕對路徑 os.path.abspath(__file__)
。
交互式 shell 中的 __file__
>>> __file__ Traceback (most recent call last): File "<input>", line 1, in <module> NameError: name '__file__' is not defined
這是因?yàn)楫?dāng)前交互式shell的執(zhí)行并不是以文件的形式加載,所以不存在__file__ 這樣的屬性。
sys.argv[0] 變量
sys.argv[0]
是它用來獲取主入口執(zhí)行文件。
#test.py import sys print __file__ print sys.argv[0]
以上 print 輸出相同的結(jié)果,因?yàn)橹鲌?zhí)行文件和__file__所屬的模塊是同一個(gè),當(dāng)我們改變?nèi)肟谖募?,區(qū)別就出現(xiàn)了。
#test.py import sys print __file__ print sys.argv[0] #test2.py import 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]
是獲得入口執(zhí)行文件路徑,__file__ 是獲得任意模塊文件的路徑。
sys.modules 的作用
既然 Python 是在 sys.path
中搜索模塊的,那載入的模塊存放在何處?答案就是 sys.modules
。模塊一經(jīng)載入,Python 會(huì)把這個(gè)模塊加入 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 解釋器啟動(dòng)之后,會(huì)把預(yù)先載入 built-in module,可以通過 sys.modules
驗(yàn)證。
>>> sys.modules['os'] <module 'os' from '/Users/x/python_dev/lib/python2.7/os.pyc'> >>>
借助 sys.modules
和 __file__,可以動(dòng)態(tài)獲取所有已加載模塊目錄和路徑。
>>> 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
來決定包的導(dǎo)入,并且系統(tǒng)包優(yōu)先級>同目錄>sys.path
,Python 中的特有屬性 __file__ 以及 sys.argv[0]
,sys.modules
都能幫助我們理解包的查找和導(dǎo)入概念,只要能正確理解 sys.path
的作用和行為,理解包的查找就不是難題了。
文中所有代碼見:github
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Python?Pygame繪制直線實(shí)現(xiàn)光線反射效果
這篇文章主要為大家詳細(xì)介紹了如何利用Python?Pygame繪制直線以實(shí)現(xiàn)光線反射效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11python3 實(shí)現(xiàn)函數(shù)寫文件路徑的正確方法
今天小編就為大家分享一篇python3 實(shí)現(xiàn)函數(shù)寫文件路徑的正確方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11關(guān)于Python文本生成的Beam?Search解碼問題
這篇文章主要介紹了Python文本生成的Beam?Search解碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07基于Python+tkinter實(shí)現(xiàn)簡易計(jì)算器桌面軟件
tkinter是Python的標(biāo)準(zhǔn)GUI庫,對于初學(xué)者來說,它非常友好,因?yàn)樗峁┝舜罅康念A(yù)制部件,本文小編就來帶大家詳細(xì)一下如何利用tkinter制作一個(gè)簡易計(jì)算器吧2023-09-09matplotlib設(shè)置顏色、標(biāo)記、線條,讓你的圖像更加豐富(推薦)
這篇文章主要介紹了matplotlib設(shè)置顏色、標(biāo)記、線條,讓你的圖像更加豐富,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Java Web開發(fā)過程中登陸模塊的驗(yàn)證碼的實(shí)現(xiàn)方式總結(jié)
Java的SSH三大Web開發(fā)框架中,對于驗(yàn)證碼這一基本功能的處理都比較得心應(yīng)手,接下來我們就來看看整理出的Java Web開發(fā)過程中登陸模塊的驗(yàn)證碼的實(shí)現(xiàn)方式總結(jié):2016-05-05Python異常處理如何才能寫得優(yōu)雅(retrying模塊)
異常就是程序運(yùn)行時(shí)發(fā)生錯(cuò)誤的信號,下面這篇文章主要給大家介紹了關(guān)于Python異常處理的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03python定時(shí)執(zhí)行指定函數(shù)的方法
這篇文章主要介紹了python定時(shí)執(zhí)行指定函數(shù)的方法,涉及Python中sleep方法延時(shí)執(zhí)行的相關(guān)使用技巧,需要的朋友可以參考下2015-05-05