python全棧開發【第十二篇】Python的模塊和包
一、模塊
1.import....
一個py文件就可以作為一個模塊
模塊的導入:直接導入文件的名字,不需要帶著後綴
模塊中的函數調用:模塊名.函數名()
導入模塊的時候做了三件事:1.首先開辟了一個新的命名空間my_moudle
2.執行了my_moudle內的代碼
3.將my_moudle裏面的名字和命名空間綁定在一起了
註意:模塊在一個程序中只會被導入一次,不會重復導入(為了節約資源)那麽,如何實現模塊在程序中只會被導入一次呢?(通過該特性可以實現單例模式)
當導入一個文件之後,會將模塊存儲在內存中,當再次導入的時候,就會到內存中查看是否導入過這個模塊,如果已經導入過了,就不用再導入了。是通過sys裏面的module方法
import sys for i in sys.modules: #查看是否導入過這個模塊 print(i)
導入的模塊有自己的命名空間(可以給導入的模塊起一個別名,就產生了一個命名空間,這個命名空間只和別名相關)
import my_moudle as mm<br>print(mm.money)
# 別名 #mysql.py def sqlparse(): print(‘from mysql sqlparse‘) #oracle.py def sqlparse(): print(‘from oracle sqlparse‘) #test.py db_type=input(‘>>: ‘) if db_type == ‘mysql‘: import mysql as db elif db_type == ‘oracle‘: import oracle as db db.sqlparse()
2.from ...import...(也支持別名)
這種形式導入啥就能用啥,不導入的一律不能用
這個被import導入的名字就相當於屬於全局變量了
from tmp import read1 read1() from tmp import read read()
參數問題和返回值問題都和函數一樣(在哪返回在哪接收,在哪傳參的在哪給參)
# from ...import... from zeze import read1 money = 1000 read1() # ------------------- from zeze import read2 def read1(): print(‘==========‘) read2() read1()
#測試:導入的函數read1,被當前位置定義的read1覆蓋掉了 from zeze import read1 def read1(): print(‘==========‘) read1()
需要特別強調的一點是:python中的變量賦值不是一種存儲操作,而只是一種綁定關系,如下:
from zeze import money,read1 money=200#將當前位置的名字money綁定到了200 print(money)#打印當前的名字 read1()#讀取zeze.py中的名字money,仍然為100
from...import *
*與all一起用的,首先會把模塊中的所有不是‘_’開頭的內容導入進來
可以通過__all__來控制導入的內容,但是只和*有關
*和__all__配合:__all__[‘read1‘,‘read2‘],all裏面導入什麽,*裏面就有什麽,如果不用all,就都導入進來了。
# from my_moudle import * # from my_moudle import _money # print(read1) # print(read2) # print(_money) # print(read)
3.把模塊當做腳本執行
#mytmp.py import mokuai print(mokuai.money) # 如果想讓自己定義的模塊,像和re模塊的調用一樣,執行的時候不顯示什麽,調用的時候才顯示,為了 讓tmp也一樣不顯示裏面的內容,就在tmp模塊裏面判斷一下 if __name__==‘__main__‘: #tmp.py money = 100 def read1(): print(‘read1‘,money) return ‘hello‘ def read2(): print(‘read2‘) if __name__==‘__main__‘: read1() read2()
4.模塊搜索路徑
模塊的查找順序是:內存中已經加載的模塊->內置模塊->sys.path路徑中包含的模塊
lib裏面放的是內置模塊
擴展模塊一般在site-packages中
sys.path:註意:搜索時按照sys.path中從左到右的順序查找,位於前的優先被查找,sys.path中還可能包含.zip歸檔文件和.egg文件,python會把.zip歸檔文件當成一個目錄去處理。
千萬不要自己定義這些你熟悉的模塊或關鍵字啊啥的作為自己的模塊名
5.編譯python文件
為了提高加載模塊的速度,強調:提高的是加載速度而絕非運行速度。python解釋器會在__pycache__目錄中下緩存每個模塊編譯後的版本,格式為:module.version.pyc。通常會包含python的版本號。
1.以pyc為後綴的就為編譯文件
2.編譯pyc文件的時候,只有在導入文件的時候才做(就是作為一個模塊的時候他才去編譯)
二、包
1. 無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的導入語法
2. 包是目錄級的(文件夾級),文件夾是用來組成py文件(包的本質就是一個包含__init__.py文件的目錄)
3. import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字同樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件
強調:
1. 在python3中,即使包下沒有__init__.py文件,import 包仍然不會報錯,而在python2中,包下一定要有該文件,否則import 包報錯
2. 創建包的目的不是為了運行,而是被導入使用,記住,包只是模塊的一種形式而已,包即模塊
註意事項:
1.關於包相關的導入語句也分為import和from ... import ...兩種,但是無論哪種,無論在什麽位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,否則非法。可以帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。
2.對於導入後,在使用時就沒有這種限制了,點的左邊可以是包,模塊,函數,類(它們都可以用點的方式調用自己的屬性)。
3.對比import item 和from item import name的應用場景:
如果我們想直接使用name那必須使用後者。
4.import
import glance.db.models glance.db.models.register_models(‘mysql‘)
5.__init__.py文件:
不管是哪種方式,只要是第一次導入包或者是包的任何其他部分,都會依次執行包下的__init__.py文件(我們可以在每個包的文件內都打印一行內容來驗證一下),這個文件可以為空,但是也可以存放一些初始化包的代碼。
6.from glance .api import *
在講模塊時,我們已經討論過了從一個模塊內導入所有*,此處我們研究從一個包導入所有*。
此處是想從包api中導入所有,實際上該語句只會導入包api下__init__.py文件中定義的名字,我們可以在這個文件中定義__all___:
7.絕對路徑導入和相對路徑導入
絕對路徑:以glance作為起始
相對路徑:用.或者..的方式最為起始(只能在一個包中使用,不能用於不同目錄內)
相對路徑只能在包中用(帶上.或者..的在該模塊下執行是報錯的)
在glance/api/version.py #絕對導入 from glance.cmd import manage manage.main() #相對導入 from ..cmd import manage manage.main()
8.單獨導入包
python全棧開發【第十二篇】Python的模塊和包