学了半天,import 到底在干啥?
文 |?軒轅御龍
來源:Python 技術「ID: pythonall」
Python憑什么就那么好用呢?
毫無疑問,大量現成又好用的內置/第三方庫功不可沒。
那我們是怎么使用它們的呢?
噢,對了~是用的import xxx這個語句。
之所以會有此一問,也是之前有一次使用PyCharm進行開發時(又)踩了個坑……
廢話少說,先講問題
像下面這樣一個項目結構:
Projetc_example |-- A|-- alpha.py|-- beta.py |-- B|-- theta.py |-- main|-- main.py假設要在main.py中導入theta.py:
#?main/main.py from?B?import?theta顯然會導致我們所不希望的問題,即Python不知道要到哪里去找這個名為B的模塊(包是一種特殊的模塊):
Traceback?(most?recent?call?last):File?"main/main.py",?line?1,?in?<module>from?B?import?theta ModuleNotFoundError:?No?module?named?'B'可是這就奇了怪了,為啥同樣的代碼,在PyCharm里運行就是好的了呢?
import的查找路徑
于是我們不辭艱辛,上下求索,原來在Python中,import語句實際上封裝了一系列過程。
1. 查找是否已導入同名模塊
首先,Python會按照import xxx中指定的包名,到sys.modules中查找當前環境中是否已經存在相應的包——不要奇怪為什么都沒有導入sys這個模塊就有sys.modules了。
sys是Python內置模塊,也就是親兒子,導入只是意思一下,讓我們這樣的外人在導入的環境中也可以使用相關接口而已,實際上相應的數據對Python而言從始至終都是透明的。
我們可以導入sys查看一下這個對象的具體內容(節省篇幅,做省略處理):
這些就都是Python一開始就已經加載好的模塊,也就是安裝好Python之后,只要一運行環境中就已經就緒的模塊——只是作為外人的我們還不能直接拿過來用,得跟Python報備一聲:“欸,我要拿您兒子來用了嗨~”
很容易可以發現,sys.modules中列出來的已加載模塊中存在明顯的不同,前面的很多模塊顯得很干凈,而后面的很多模塊都帶有from yyy'的字樣,并且這個yyy看起來還像是一個路徑。
這就關系到我們接下來要講的步驟了。
2. 在特定路徑下查找對應模塊
前面我們講到了,當我們導入某個模塊時,Python先會去查詢sys.modules,看其中是否存在同名模塊,查到了那當然皆大歡喜,Python直接把這個模塊給我們用就好了,畢竟兒子那么多,借出去賺點外快也是好事兒不是?
可問題在于:那要是沒找到呢?
這顯然是一個很現實的問題。畢竟資源是有限的,Python不可能把你可能用到的所有模塊全都一股腦給加載起來,否則這樣男上加男加男加男……誰也頂不住啊不是(大霧
于是乎就有人給Python出了個主意:那你等到要用的時候,再去找他說他是你兒子唄
Python:妙哇~
有了這個思路,Python就指定了幾家特定的酒樓,說:“凡是去消費的各位,都可以給我當兒子。”
就這樣,一些本來不是Python親兒子的人,出于各種原因聚集到了這幾家酒樓,以雇傭兵的身份隨時準備臨時稱為Python的兒子。
這可就比周文王開局就收100個義子優雅多了,養家糊口的壓力也就沒那么大了(Python:什么?我的親兒子都不止100個?你說什么?聽不見啊——
回到正經的畫風來——
實際上,在Python中,sys.path維護的就是這樣一個py交易的結果~~(誒?好像莫名發現了什么),其中保存的內容就是這幾家“指定酒樓”,也就是當Python遇到不認識的兒子~~模塊時,就會去實地查找的路徑。
我們也可以打印出來看看具體內容:
>>>?sys.path ['',?'E:\\Anaconda\\Anaconda\\python37.zip',?'E:\\Anaconda\\Anaconda\\DLLs',?'E:\\Anaconda\\Anaconda\\lib',?'E:\\Anaconda\\Anaconda',?'E:\\Anaconda\\Anaconda\\lib\\site-packages',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32\\lib',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\Pythonwin']大體上就是安裝環境時配置的一些包所在路徑,其中第一個元素代表當前所執行腳本所在的路徑。
也正是因此,我們可以在同一個目錄下,大大方方地調用其他模塊。
3. 將模塊與名字綁定
找到相應的非親生模塊還沒完,加載了包還得為它分配一個指定的名字,我們才能在腳本中使用這個模塊。
當然多數時候我們感知不到這個過程,因為我們就是一個import走天下:
import?sys import?os import?requests這個時候我們指定的模塊名,實際上也是指定的稍后用來調用相應模塊的對象名稱。
換個更明顯的:
import?requests?as?req如果這個時候只使用了第二種方式來導入requests這個模塊,那么很顯然在之后的程序流程中,我們都不能使用requests這個名字來調用它而應當使用req。
這就是Python導入過程中的名稱綁定,本質上與正常的賦值沒有太大區別,加載好了一個對象之后,然后為這個對象賦一個指定的變量名。
當然即使是已經加載好的模塊,我們也可以利用這個名稱綁定的機制為它們取別名,比如:
>>>?import?sys >>>?import?sys?as?sy >>>?sys.path ['',?'E:\\Anaconda\\Anaconda\\python37.zip',?'E:\\Anaconda\\Anaconda\\DLLs',?'E:\\Anaconda\\Anaconda\\lib',?'E:\\Anaconda\\Anaconda',?'E:\\Anaconda\\Anaconda\\lib\\site-packages',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32\\lib',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\Pythonwin'] >>>?sy.path ['',?'E:\\Anaconda\\Anaconda\\python37.zip',?'E:\\Anaconda\\Anaconda\\DLLs',?'E:\\Anaconda\\Anaconda\\lib',?'E:\\Anaconda\\Anaconda',?'E:\\Anaconda\\Anaconda\\lib\\site-packages',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\win32\\lib',?'E:\\Anaconda\\Anaconda\\lib\\site-packages\\Pythonwin'] >>>?sys?==?sy True問題解決
好了,上面就是對Python導入機制的大致介紹,但是說了半天,我們的問題還沒有解決:在項目中如何簡潔地跨模塊導入其他模塊?
在使用PyCharm的時候倒是一切順遂,因為PyCharm會自動將項目的根目錄加入到導入的搜索路徑,也就是說像下面這樣的項目結構,在任意模塊中都可以很自然地通過import A導入模塊A,用import B導入模塊B。
Projetc_example |-- A|-- alpha.py|-- beta.py |-- B|-- theta.py |-- main|-- main.py但是在非IDE環境中呢?或者說就是原生的Python環境中呢?
很自然地我們就會想到:那就手動把項目根目錄加入到sys.path中去嘛。說起來也跟PyCharm做的事沒差呀
可以,貧道看你很有悟性,不如跟我去學修仙吧
所以我們就通過sys和os兩個模塊七搞八搞(這兩個模塊以前有過介紹,不再贅述)——
噔噔噔噔——好使了
#?Peoject_example/A/alpha.py print("name:?"?+?__name__) print("file:?"?+?__file__)def?al():print("Importing?alpha?succeeded.")main.py中則加入一個邏輯,在sys.path中增加一個項目根目錄:
import?os import?syssys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))import?A.alphaA.alpha.al()#?name:?A.alpha #?file:?*\Project_example\A\alpha.py #?Importing?alpha?succeeded.大功告成,風緊扯呼~
總結
本文借由一個易現問題引出對Python導入機制的介紹,實際上限于篇幅,導入機制只是做了一個概覽,具體的內容還要更加復雜。本文講到的這三步則適用于比較常見的情形,了解了這三步也足以應付很多問題了。更多內容還是留待大家自行探索,當然后續也可能會有文章進一步講解——誰知道呢哈哈~~(又挖坑了)~~
參考資料
https://docs.python.org/zh-cn/3/reference/import.html
老規矩,兄弟們還記得么,右下角的 “在看” 點一下,如果感覺文章內容不錯的話,記得分享朋友圈讓更多的人知道!
【代碼】
https://github.com/JustDoPython/python-examples/tree/master/xuanyuanyulong/2020-10-13-import-system
由于微信平臺算法改版,公號內容將不再以時間排序展示,如果大家想第一時間看到我們的推送,強烈建議星標我們和給我們多點點【在看】。星標具體步驟為:
總結
以上是生活随笔為你收集整理的学了半天,import 到底在干啥?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不想跑数了,数据分析师的前途在哪里?
- 下一篇: 瞧瞧,这样的『函数』才叫 Pythoni