模塊就是一組功能的集合體,咱們的程序能夠導入模塊來複用模塊裏的功能。每個 Python 腳本.py文件均可以被當成是一個模塊。模塊以磁盤文件的形式存在。當一個模塊變得過大,而且驅動了太多功能的話,就應該考慮拆一些代碼出來另外建一個模塊。模塊裏的代碼能夠是一段直接執行的腳本,也能夠是一堆相似庫函數的代碼,從而能夠被別的模塊導 入(import)調用。模塊能夠包含直接運行的代碼塊、類定義、 函數定義或這幾者的組合。html
模塊分類:Python標準庫模塊、Python第三方模塊、應用程序自定義模塊。python
Python標準庫模塊:有些模塊直接被構建在解析器裏,這些雖然不是一些語言內置的功能,可是他卻能很高效的使用,甚至是系統級調用也沒問題。這些組件會根據不一樣的操做系統進行不一樣形式的配置,好比 winreg (Windows註冊表訪問)這個模塊就只會提供給 Windows 系統。應該注意到這有一個特別的模塊 sys ,它內置在每個 Python 解析器中。可參考:http://www.javashuo.com/article/p-ncoptfrs-cm.html程序員
https://blog.csdn.net/sadfishsc/article/details/10390065app
Python第三方模塊:非在解析器裏的他人寫的python腳本,可到官方提供的第三方模塊網址查找、下載:https://pypi.org/。dom
應用程序自定義模塊:本身寫的python腳本。ide
模塊做用:函數
1.可把程序分紅一個個的文件,這樣作程序的結構更清晰,方便管理。測試
2.文件裏實現的功能可重複利用,提升開發效率。編碼
在Python中用關鍵字import來引入某個模塊,好比要導入模塊time,就能夠在文件最開始或使用以前的地方用 import 來引入。spa
語法:import 模塊名
在調用模塊中的函數時,必須加上模塊名調用,由於可能存在多個模塊中含有相同名稱的函數,此時,若是隻是經過函數名來調用,解釋器沒法知道到底要調用哪一個函數。爲了不這樣的狀況,調用函數時,必須加上模塊名。
import加載的模塊分爲四個通用類別:
1 使用python編寫的.py文件
2 已被編譯爲共享庫或DLL的C或C++擴展
3 包好一組模塊的包,把一系列模塊組織到一塊兒的文件夾(注:文件夾下有一個__init__.py文件,該文件夾稱之爲包)
4 使用C編寫並連接到python解釋器的內置模塊
import time time.sleep(1) #時間睡眠 # sleep() #會報錯
咱們能夠從sys.module中找到當前已經加載的模塊,sys.module是一個字典,內部包含模塊名與模塊對象的映射,該字典決定了導入模塊時是否須要從新導入。
一行導入多個模塊
import time,random #模塊之間用逗號隔開 print(time.time()) print(random.randint(1,3))
導入模塊重命名:import ... as
有時候你導入的模塊名稱已經在你的程序中使用了, 或者你不想使用現有的名稱。可使用一個新的名稱替換原始的名稱。
import time as tm print(tm.time())
python模塊搜索路徑
在任何一個python程序啓動時,都會將模塊的搜索路徑收集到sys模塊的path屬性中(sys.path
)。當python須要搜索模塊文件在何處時,首先搜索python解釋器的內置模塊(如time模塊),若是不是內置模塊,則搜索sys.path中的路徑列表,搜索時會從該屬性列出的路徑中按照從前向後的順序進行搜索,而且只要找到就當即中止搜索該模塊文件。因此若是當前路徑或 PythonPATH中存在與標準module一樣的module,則會覆蓋標準module。也就是說,若是當前目錄下存在xml.py,那麼在執行import xml時,導入的是當前目錄下的module,而不是系統標準的xml.py。
import sys print(sys.path)
import語句是導入模塊中的全部屬性,而且訪問時須要使用模塊變量來引用,Python的from語句讓你從模塊中導入一個指定的部分到當前命名空間中。使用這種方式導入,不會整個模塊導入到當前命名空間,它只會將import的內容導入。from.....import 也支持as模式,給導入的模塊重命名。
from time import time,sleep start_time = time() print(start_time) sleep(2) stop_time = time() print(stop_time) print(stop_time-start_time)
導入一個模塊的全部內容也可使用from…import*,但不推薦使用,由於可能形成變量命名衝突。
from time import * print(time()) #可直接使用time模塊的全部功能,不需在前綴加模塊名
命名衝突示例
from time import * #假如咱們不知道time模塊裏是否有time(),但在導入time模塊的下方本身定義了一個名爲time的函數 def time(): return '本身定義的time函數被調用' #在本身定義的time函數下方使用from time import * # from time import * print(time()) #函數名即變量名儲存的是函數對象的引用,同名函數會存在引用覆蓋。
注意:當Python程序導入其餘模塊時,要避免循環導入,,即A文件導入了B,B文件又導入了A.,否則總會出意向不到的問題….
使用模塊能夠避免函數名和變量名衝突。相同名字的函數和變量徹底能夠分別存在不一樣的模塊中,所以,咱們本身在編寫模塊時,沒必要考慮名字會與其餘模塊衝突。可是也要注意,儘可能不要與內置函數名字衝突。爲了不模塊名衝突,Python又引入了按目錄來組織模塊的方法,稱爲包(Package)。
包是一種管理 Python 模塊命名空間的形式,採用"點模塊名稱"。好比一個模塊的名稱是 A.B, 那麼他表示一個包 A中的子模塊B
目錄中只有包含一個叫作__init__.py的文件纔會被認做是一個包,__init__.py
文件是必須存在的,不然,Python就把這個目錄當成普通目錄,而不是一個包。__init__.py
能夠是空文件,也能夠有Python代碼。當包看成模塊被導入時,__init__.py就會被執行加載。
在導入包的時候,Python會從sys.path中的目錄來尋找這個包中包含的子目錄。
Notes: 本身建立模塊時要注意命名,不能和Python自帶的模塊名稱衝突。例如,系統自帶了sys模塊,本身的模塊就不可命名爲sys.py,不然將沒法導入系統自帶的sys模塊。
類的屬性:
__doc__ 文檔字符串
__name__ 類名稱
__bases__ 父類組成的元組
__dict__ 保存類方法和變量等的字典
實例的屬性:
__class__ 實例所屬的類
__dict__ 保存實例數據的字典
模塊的屬性:
__dict__ 與模塊相關的字典
__name__ 模塊的名稱
__file__ 模塊文件的絕對路徑
導入包:
導入包與導入模塊的方式是同樣的。當執行導入包時,__init__.py就會被執行加載。因此包其實也是個模塊,__init__.py
能夠是空文件,不過會影響from <包名> import * 和 import <包名> 這兩種導入方式。
建立__init__.py文件:
目錄中只有包含了叫作__init__.py的文件,才能被程序認做是包,模塊才能被導入成功。如今咱們就在msg文件夾下建立一個__init__.py文件,而且在文件中寫入__all__=[ 'module_name', 'module_name' ]。
能夠在__init__.py中編寫其餘內容,在導入時,這些編寫的內容就會被執行。
能夠在__init__.py中向sys.path添加當前被調用模塊路徑。
__all__總結:
編寫Python代碼(不建議在__init__中寫python模塊,能夠在包中在建立另外的模塊來寫,儘可能保證__init__.py簡單)。
模塊中不使用__all__屬性,則導入模塊內的全部公有屬性,方法和類 。 模塊中使用__all__屬性,包中使用__all__屬性,則表示只導入__all__中指定的屬性,定義了當咱們使用 from <module> import * 導入某個模塊/包的時候能導出的符號(這裏表明變量,函數,類等) (固然下劃線開頭的變量,方法和類除外)。
須要注意的是 __all__ 隻影響到了 from <package> import * 或 import <package> 這種導入方式, 對於 from <module|package> import <member> 導入方式並無影響,仍然能夠從外部導入。
reload()簡介:
不管時import仍是from,默認狀況下,模塊在第一次被導入以後,其餘的導入都再也不有效。若是此時在另外一個窗口中改變並保存了模塊的源代碼文件,也沒法更新該模塊。這樣設計緣由在於,導入是一個開銷很大的操做(導入必須找到文件,將其編譯成字節碼,而且運行代碼),以致於每一個文件、每一個程序運行不可以重複多於一次。當一個模塊被導入到一個腳本,模塊代碼只會被執行一次。所以,若是你想從新執行模塊裏代碼,能夠用reload()函數,該函數會從新導入以前導入過的模塊。reload()是imp模塊中的一個函數,因此要使用imp.reload()以前,必須先導入imp,它的參數是一個已經成功被導入過的模塊變量。也就是說該模塊必須在內存中已經有本身的模塊對象。reload()會從新執行模塊文件,並將執行獲得的屬性徹底覆蓋到原有的模塊對象中。也就是說,reload()會從新執行模塊文件,但不會在內存中創建新的模塊對象,因此原有模塊對象中的屬性可能會被修改。語法:reload(module_name)。
import random def mul(x,y): return x*y print(random.randint(3,3)) #此時random.randint()是隨機函數。 random.randint = mul #變爲乘法函數 print(random.randint(3,3)) from imp import reload reload(random) print(random.randint(3,3)) #變回隨機函數。
py文件分兩種:用於執行的程序文件和用於導入的模塊文件。當直接使用python a.py
的時候表示a.py是用於執行的程序文件,經過import/from方式導入的py文件是模塊文件。
__name__
屬性用來區分py文件是程序文件仍是模塊文件:
__main__
對於python來講,由於隱式自動設置,該屬性就有了特殊妙用:直接在模塊文件中經過if __name__ == "__main__"
來判斷,而後寫屬於執行程序的代碼,若是直接用python執行這個文件,說明這個文件是程序文件,因而會執行屬於if代碼塊的代碼,若是是被導入,則是模塊文件,if代碼塊中的代碼不會被執行。
導入模塊的過程:
python的import是在程序運行期間執行的,並不是像其它不少語言同樣是在編譯期間執行。也就是說,import能夠出如今任何地方,只有執行到這個import行時,纔會執行導入操做。且在import某個模塊以前,沒法訪問這個模塊的屬性。
python在import導入模塊時,首先搜索模塊的路徑,而後編譯並執行這個模塊文件。雖然歸納起來只有兩個過程,但實際上很複雜。
Python中全部加載到內存的模塊都放在sys.modules。sys.modules是一個全局字典,該字典是python啓動後就加載在內存中。每當程序員import一個模塊文件時,首先會在這個字典查找是否已經加載了此模塊,若是加載了則只是將模塊的名字加入到正在調用import的模塊的Local名字空間中(若是在全局做用域導入模塊,則把模塊名加入全局命名稱空間,若是是在局部做用域導入模塊,則模塊名加入局部名稱空間)。若是沒有加載則從sys.path目錄中按照模塊名稱查找模塊文件,模塊文件能夠是py、pyc、pyd,找到後建立新的module對象(此時module對象的 __dict__ 屬性爲空),並將模塊名與module對象的引用加入字典sys.modules中,而後編譯、執行模塊文件載入內存,並填充module對象的屬性__dict__,按照必定的規則將一些結果放進這個module對象中,最後將模塊名稱導入到當前的Local名字空間。
注意細節:編譯、執行模塊文件、將結果保存到module對象中。
關於編譯、執行模塊文件的細說:
模塊第一次被導入的時候,會進行編譯,並生成.pyc字節碼文件,而後在python工做目錄的環境下執行這個pyc文件,而非模塊所在的目錄環境。當模塊被再次導入時,若是檢查到pyc文件的存在,且和源代碼文件的上一次修改時間戳mtime徹底對應(也就是說,編譯後模塊文件的源代碼沒有進行過修改),則直接裝載這個pyc文件並執行,不會再進行額外的編譯過程。固然,若是修改過模塊文件的源代碼,將會從新編譯獲得新的pyc文件。
注意,並不是全部的py文件都會生成編譯獲得的pyc文件,對於那些只執行一次的程序文件,會將內存中的編譯結果在執行完成後直接丟棄(多數時候如此,但仍有例外,好比使用compileall模塊能夠強制編譯成pyc文件),但模塊會將內存中的編譯結果持久化到pyc文件中。另外,運行字節碼pyc文件並不會比直接運行py文件更快,執行它也同樣是一行行地解釋、執行,惟一快的地方在於導入裝載的時候無需從新編譯而已。
執行模塊文件(已完成編譯)的時候,按照通常的執行流程執行:一行一行地、以代碼塊爲單元執行。通常地,模塊文件中只用來聲明變量、函數等屬性,以便提供給導入它的模塊使用,而不該該有其餘任何操做性的行爲,好比print()操做不該該出如今模塊文件中,但這並不是強制。
總之,執行完模塊文件後,這個模塊文件將有一個本身的全局名稱空間,在此模塊文件中定義的變量、函數等屬性,都會記錄在此名稱空間中。
最後,模塊的這些屬性都會保存到模塊對象中。因爲這個模塊對象賦值給了模塊變量module_name,因此經過變量module_name能夠訪問到這個對象中的屬性(好比變量、函數等),也就是模塊文件內定義的全局屬性。
參考連接:https://www.cnblogs.com/qq78292959/archive/2013/05/17/3083961.html
https://www.jianshu.com/p/178c26789011
目錄結構package目錄與test目錄是同級的:
print('package/package2目錄下的__init__模塊被加載')
print('package/package2目錄下的module1.py執行加載') print('package/package2目錄下module1模塊的__name__屬性值爲:{}'.format(__name__))
'''導入與父目錄的父目錄同級的模塊''' # import test.module1 as md from test import module1
__all__ = ['module1'] print('package目錄下的__init__模塊被加載')
print('package目錄下的module1.py執行加載') print('package目錄下的module1模塊的__name__屬性值爲:{}'.format(__name__)) def add(x,y): return x+y def mul(x,y): return x*y
'''同目錄下的模塊導入方式''' # import module1 # from package import module1 # from module2 import * #不推薦使用,避免命名衝突 # print('package目錄下的module1.py執行加載') # print('module1模塊的__name__屬性值爲:{}'.format(__name__)) # def add(x,y,z): # return x+y+z # def mul(x,y,z): # return x*y*z # print(module1.add(2,3)) '''導入與父目錄同級的模塊的方法''' # import test #導入test包,實質上是導入test目錄下的 __init__模塊,此模塊有什麼屬性,導入的test就有什麼屬性。 # print(test.module1.__name__) # import test.module1 as md # from test import module1 '''導入同目錄下的包''' # import package2.module1 as md # from package2 import module1
print('test目錄下的__init__.py被加載') __all__ = ['module1'] # 若容許經過包名導入全部模塊,必須給__all__實現賦值 from test import * #表示導入同目錄的全部模塊
print('test目錄下的module1被加載')
若python解釋器沒法找到可根據模塊的所在目錄給sys.path添加搜索路徑:
或是:
import sys,os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) from bao1 import a1 a1.aa1(99)
編寫一個hello.py
的模塊
1 #!/usr/bin/env python3 2 # -*- coding: utf-8 -*- 3 4 ' a test module ' 5 6 __author__ = 'Michael Liao' 7 8 import sys 9 10 def test(): 11 args = sys.argv # argv參數用列表存儲命令行的全部參數 12 if len(args)==1: # 當列表長度爲1時即只有一個參數時 13 print('Hello, world!') 14 elif len(args)==2: # 當命令行有兩個參數時 15 print('Hello, %s!' % args[1]) 16 else: 17 print('Too many arguments!') 18 19 if __name__=='__main__': 20 test()
第1行和第2行是標準註釋,第1行註釋可讓這個hello.py文件直接在Unix/Linux/Mac上運行,第2行註釋表示.py文件自己使用標準UTF-8編碼;
第4行是一個字符串,表示模塊的文檔註釋,任何模塊代碼的第一個字符串都被視爲模塊的文檔註釋;
第6行使用__author__
變量把做者寫進去,這樣當你公開源代碼後別人就能夠瞻仰你的大名;
第8行是導入sys模塊,導入sys
模塊後,咱們就有了變量sys
指向該模塊,利用sys這個變量,就能夠訪問sys模塊的全部功能。sys
模塊有一個argv
變量,用list
存儲了命令行的全部參數。argv
至少有一個元素,由於第一個參數永遠是該.py文件的名稱,例如:運行python3 hello.py
得到的sys.argv
就是['hello.py']
,注意這裏python3
不算是參數;運行python3 hello.py Michael
得到的sys.argv
就是['hello.py', 'Michael]
。
第19行表示當咱們在命令行運行hello
模塊文件時,Python解釋器把一個特殊變量__name__
置爲__main__
,而若是在其餘地方導入該hello
模塊時,if
判斷將失敗,所以,這種if
測試可讓一個模塊經過命令行運行時執行一些額外的代碼,最多見的就是運行測試。
以上就是Python模塊的標準文件模板,固然也能夠所有刪掉不寫,可是,按標準辦事確定沒錯。