原文引至:前端小吉米
對於python中的模塊和包, 我簡直就想說, js nmlgb 就是一個 trash... 在前端寫js根本就沒有什麼模塊和包, 所有都是全局... 真lj... css
暢快了. 寫了這麼久的js, 連內部的模塊的包都搞的這麼複雜... 艹...
在python中, 已經定義好了完美的模塊和包的引用機制.
咱們先來看看Modulehtml
在python中, 模塊實際上,就至關於與業務邏輯解耦的可重用的一些函數方法. 因此, 咱們能夠預先定義一個模塊:前端
// 命令爲sam.py def add(a,b): return a+b
以後在同目錄中,打開一個 Terminator.
接着輸入:node
>>> import sam >>> sam.add(1,2) //結果爲: 3
實際上, 這就是一個簡單的模塊. 但,當咱們導入的時候, 會在Module的目錄中生成一個.pyc文件, 該其實就是用來對Module進行緩存,並編譯爲Binary 文件, 以便py之後再次引入.
如今, 咱們已經學會如何寫入Module,引入Module. 這裏,咱們須要更進一步去探索, python是如何進行Module Path的搜索的.python
在nodeJS中, 他的搜索方式是, 先看內部定義的Module 有沒有. 沒有的話,則會開始尋找每一層的node_modules. 而後在裏面搜索你的文件.js
那麼在py中,他是怎樣一個過程呢?
py將搜索路徑,放在了sys.path中.咱們能夠查看一下. sys.path裏面的內容.編程
import sys sys.path
而後就會出現, 一些路徑,好比這個:緩存
['', 'C:\\Python33\\Lib\\lib-dynload', 'C:\\Windows\\system32\\python33.zip', 'C:\\Python33\\DLLs', 'C:\\Python33\\lib', 'C:\\Python33\\plat-darwin', 'C:\\Python33\\lib\\site-packages']
能夠看到, 第一個爲空, 他實際表明的就是current directory.
具體的順序是:app
當前目錄編程語言
sys.path定義的相關目錄ide
安裝依賴的目錄
因此, 若是你想自定義本身的Module 直接添加在sys.path裏面便可.
那應該怎樣進行添加呢?
實際上, 這就是查找關於sys.path的方法了. 還記得help()嗎?
查找後,咱們基本上都會明白了. md, 這不就是list嗎?
那剩下的不就是調用,list的方法進行添加和刪除嗎?
通常而言,python的工做目錄是放在對應的pythonLib文件夾內.這裏,我將我經常使用的py 模塊路徑添加進去
sys.path.append('/Users/jimmy_thr/Documents/pythonLib')
以後, 我只要將我寫好的Module 放在指定的文件內便可.
上面, 咱們只是學會使用基本的Module 導入, 實際上,py提供了 更加豐富的Module statement.
好比, 重命名, 指定導入, 全導入
這個算是一個py Module的一個附加值吧.
具體用法很簡單.
import sam as sb sb.add(1,2)
就醬, 實際上,就是使用as
將模塊的名字換一個. 而且, 換了以後sam, 也就不存在了.
直接看demo吧:
//直接導入 add方法 from sam import add // 也能夠導入多個 from sam import add,minus
這樣導入的結果也是, 不能使用sam.
若是你想, 將module裏面全部的方法都導入的話, 直接使用*
便可
from sam import *
不過, 真強烈不建議這麼作. 由於, 並無什麼卵用, 而且, 萬一出現什麼bug, 都不知道這個方法哪來的.
在nodeJS中, 他的模塊引用是值引用類型, 即就是, 一次引用以後, 就會放在緩存裏面, 之後若是在引用的話, 會直接從緩存裏面取了.
看一個demo:
def add(a,b): return a+b print(add(1,2)) //接着,我屢次引用 >>> import sam 3 >>> import sam
只會出現一次, 說明, sam Module 只能導入一次. 其他的就 nonesense. 可是,若是你的模塊是內部循環型的, 那這樣不就go die了嗎?
hehe ~ py 早教看到這一點了, 在內置的imp中提供了reload方法, 來幫助咱們實現, 模塊的引用更新
>>> import imp >>> imp.reload(sam) 3
最後在補充一個dir(module)方法. 他的做用,就是用來查看指定Module當中的全局變量和函數名.
>>> dir(sam) ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'add']
其他的用underscore來鏈接的, 是py中 module的一部分. 比較重要的看一下__name__便可. 他是用來表示,你當前所在的程序是模塊,仍是主程序.
若是你是主程序則 __name__ 爲 main
若是爲模塊則 __name__ 爲 你的模塊名
另外,若是你忽略參數, 直接使用dir()的話,就是用來查看當前 全局中的變量和函數名.
>>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '__warningregistry__', 'get', 'imp', 'sam', 'set']
但,若是你導入一個內置模塊的話, 好比: copy
>>> import copy >>> dir(copy) ['Error', 'PyStringMap', '_EmptyClass', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', ...]
仔細觀察, 裏面的內置屬性, 會看到多出一個叫__all__
的屬性. 這其實和下面所說的包有一些關係. 實際上, __all__ 的做用, 是提供公共接口的, 但實際上, 當咱們導入方法的時候, 每每會所有倒入.好比這樣.
import copy
那麼此時, __all__ 對於這種方法是沒有任何做用, 該語句就是用來導入copy下全部的全局變量.
如今, 假設 當前模塊sam.py下有2個方法,add,minus.
我將__all__ 設置爲
__all__ = ['add']
咱們來試驗一下二者的區別:
//首先導入: >>> import sam >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'sam'] >>> dir(sam) ['__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'add', 'minus']
能夠看到,有了sam這個模塊名. 而且, 查看sam中,會看到有add和minus方法.
而後,咱們換一種方式導入:
>>> from sam import * >>> dir() ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'add']
咱們會發現, minus不見了.
因此, 這裏咱們就能夠搞懂了__all__ 究竟是用來作什麼的.
__all__: 用來設置模塊的公共接口. 而且只針對於 from module import *
的語句
最後在說一下,其中的另外兩個默認屬性 __doc__
,__file__
__doc__: 實際上,就是咱們使用help()函數查看的內容. 內容具體就是咱們寫在模塊開頭或者函數開頭的註釋
__file__: 模塊真實的文件路徑, 若是你想查看源碼的時候就很重要了.
放圖:
說完了,py中的Module, 接着就是最讓你66的包. Module只是幫助咱們完成了一個組件的一些小功能, 可是若是咱們想要寫一個能夠調用的總體組件的話, 那麼一個single Module顯然是不夠了. 因此,py 推出了package 來幫助咱們完成這個巨大的工程(project). 咱們能夠經過個文件,調用,該組件下全部的方法. 好比,咱們須要寫一個html的評論框, 那麼裏面確定會設計, HTML,css,js樣式設計, 接收評論,發佈評論等不少功能. 在包裏面, 咱們就能夠把這些小功能進行拆分,達到複用的效果.
先看張圖:
這實際上, 就是咱們python包的簡單格式, 在每一個文件根目錄都會存在__init.py__ 文件. 他的做用實際上,就是用來定義, 引用包時, 暴露的相關接口. 而關鍵的關鍵, 就是上面提到的__all__ 內置的默認關鍵字. how to use?
請, stackoverflow.
__init__.py就是一個導入文件
如今,咱們來寫一個簡單的包, 以上圖爲例。
在Game的根目錄下, __init__.py內容爲:
__all__ = ['Sound','Image','Level'] from Game import Sound,Image,Level
而後,咱們就能夠直接應用Game 包了.
>>>import Game >>>Game.Sound.xxx
這裏,須要說明的是, 關於包的導入, 其實用不用all不是很重要, 換句話說, 應該是不推薦, 由於前文咱們已經瞭解到, __all__ 生效的機制是 使用 from xx import *
這樣的語句. 而這樣作的實際效果是, 徹底破壞了python的namespace機制, 也是編程語言中最重要的一個. 因此, 給的建議就是, 儘可能放棄all的使用, 直接使用 import 來判斷你須要導出那些公共的接口便可.
引用一段話:
Leaving an __init__.py file empty is considered normal and even a good practice, if the package’s modules and sub-packages do not need to share any code.
出自: python guider