python之塊包導入
一、模塊
1、什麽是模塊
常見的場景:一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的後綴。
但其實import加載的模塊分為四個通用類別:
1 使用python編寫的代碼(.py文件)
2 已被編譯為共享庫或DLL的C或C++擴展
3 包好一組模塊的包
4 使用C編寫並鏈接到python解釋器的內置模塊
2、為什麽要使用模塊
如果你退出python解釋器然後重新進入,那麽你之前定義的函數或者變量都將丟失,因此我們通常將程序寫到文件中以便永久保存下來,需要時就通過python test.py方式去執 行,此時test.py被稱為腳本script。
隨著程序的發展,功能越來越多,為了方便管理,我們通常將程序分成一個個的文件,這樣做程序的結構更清晰,方便管理。這時我們不僅僅可以把這些文件當做腳本去執行, 還可以把他們當做模塊來導入到其他的模塊中,實現了功能的重復利用
3、如何使用模塊
3.1 import
示例文件:spam.py,文件名spam.py,模塊名spam
spam.py print(‘from the spam.py‘) money=1000 def read1(): print(‘spam->read1->money‘,money)def read2(): print(‘spam->read2 calling read‘) read1() def change(): global money money=0
3.1.1 模塊只在模塊名第一次遇到導入import語句時才執行(import語句是可以在程序中的任意位置使用的,且針對同一個模塊很import多次,為了防止你重復導入,python的優化 手段是:第一次導入後就將模塊名加載到內存了,後續的import語句僅是對已經加載大內存中的模塊對象增加了一次引用,不會重新執行模塊內的語句)
#test.py import spam #只在第一次導入時才執行spam.py內代碼,此處的顯式效果是只打印一次‘from the spam.py‘,當然其他的頂級代碼也都被執行了,只不過沒有顯示效果. import spam import spam import spam ‘‘‘ 執行結果: from the spam.py ‘‘‘
我們可以從sys.module中找到當前已經加載的模塊,sys.module是一個字典,內部包含模塊名與模塊對象的映射,該字典決定了導入模塊時是否需要重新導入。
3.1.2 每個模塊都是一個獨立的名稱空間,定義在這個模塊中的函數,把這個模塊的名稱空間當做全局名稱空間,這樣我們在編寫自己的模塊時,就不用擔心我們定義在自己模塊 中全局變量會在被導入時,與使用者的全局變量沖突
3.1.3總結:首次導入模塊spam時會做三件事:
1.為源文件(spam模塊)創建新的名稱空間,在spam中定義的函數和方法若是使用到了global時訪問的就是這個名稱空間。
2.在新創建的命名空間中執行模塊中包含的代碼,見初始導入import spam
3.創建名字spam來引用該命名空間
3.1.4 為模塊名起別名
import spam as sm
3.1.5在一行導入多個模塊
import sys,os,re
3.2 from...import...
3.2.1 對比import spam,會將源文件的名稱空間‘spam‘帶到當前名稱空間中,使用時必須是spam.名字的方式
而from 語句相當於import,也會創建新的名稱空間,但是將spam中的名字直接導入到當前的名稱空間中,在當前名稱空間中,直接使用名字就可以了、
from spam import read1,read2
這樣在當前位置直接使用read1和read2就好了,執行時,仍然以spam.py文件全局名稱空間
如果當前有重名read1或者read2,那麽會有覆蓋效果。
需要特別強調的一點是:python中的變量賦值不是一種存儲操作,而只是一種綁定關系
3.2.2 也支持as
from spam import read1 as read
3.2.3 也支持導入多行
from spam import (read1,
read2, money)
3.2.4 from spam import * 把spam中所有的不是以下劃線(_)開頭的名字都導入到當前位置,大部分情況下我們的python程序不應該使用這種導入方式,因為*你不知道你導入什麽名字,很有可能會覆蓋掉你之前已經定義的名字。而且可讀性極其的差,在交互式環境中導入時沒有問題。
可以使用__all__來控制*(用來發布新版本)
在*.py中新增一行
__all__=[‘money‘,‘read1‘] #這樣在另外一個文件中用from spam import *就這能導入列表中規定的兩個名字
可以使用__all__來控制*(用來發布新版本)
如果spam.py中的名字前加_,即_money,則from spam import *,則_money不能被導入
3.2.5 考慮到性能的原因,每個模塊只被導入一次,放入字典sys.module中,如果你改變了模塊的內容,你必須重啟程序,python不支持重新加載或卸載之前導入的模塊,
3.3 把模塊當做腳本執行
我們可以通過模塊的全局變量__name__來查看模塊名:
當做腳本運行:
__name__ 等於‘__main__‘
當做模塊導入:
__name__=
作用:用來控制.py文件在不同的應用場景下執行不同的邏輯
if __name__ == ‘__main__‘:
3.4模塊搜索路徑
python解釋器在啟動時會自動加載一些模塊,可以使用sys.modules查看
在第一次導入某個模塊時(比如spam),會先檢查該模塊是否已經被加載到內存中(當前執行文件的名稱空間對應的內存),如果有則直接引用
如果沒有,解釋器則會查找同名的內建模塊,如果還沒有找到就從sys.path給出的目錄列表中依次尋找spam.py文件。
所以總結模塊的查找順序是:內存中已經加載的模塊->內置模塊->sys.path路徑中包含的模塊
3.5編譯python文件
為了提高加載模塊的速度。python解釋器會在__pycache__目錄中下緩存每個模塊編譯後的版本,格式為: module.version.pyc。通常會包含python的版本號。例如,在 CPython3.3版本下,spam.py模塊會被緩存成__pycache__/spam.cpython-33.pyc。這種命名規範保證了編譯後的 結果多版本共存。
二、包
包是一種通過使用‘.模塊名’來組織python模塊名稱空間的方式。
1. 無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的導入語法
2. 包是目錄級的(文件夾級),文件夾是用來組成py文件(包的本質就是一個包含__init__.py文件的目錄)
3. import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字同樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件
強調:
1. 在python3中,即使包下沒有__init__.py文件,import 包仍然不會報錯,而在python2中,包下一定要有該文件,否則import 包報錯
2. 創建包的目的不是為了運行,而是被導入使用,記住,包只是模塊的一種形式而已,包即模塊
_init__.py文件
不管是哪種方式,只要是第一次導入包或者是包的任何其他部分,都會依次執行包下的__init__.py文件(我們可以在每個包的文件內都打印一行內容來驗證一下),這個文件可以為空,但是也可以存放一些初始化包的代碼。
2.2 from glance.api import *
在講模塊時,我們已經討論過了從一個模塊內導入所有*,此處我們研究從一個包導入所有*。
此處是想從包api中導入所有,實際上該語句只會導入包api下__init__.py文件中定義的名字,我們可以在這個文件中定義__all___:
2.3 絕對導入和相對導入
導入和相對導入兩種方式:
絕對導入:以glance作為起始
相對導入:用.或者..的方式最為起始(只能在一個包中使用,不能用於不同目錄內)
特別需要註意的是:可以用import導入內置或者第三方模塊(已經在sys.path中),但是要絕對避免使用import來導入自定義包的子模塊(沒有在sys.path中),應該使用 from... import ...的絕對或者相對導入,且包的相對導入只能用from的形式。
2.4單獨導入包
單獨導入包名稱時不會導入包中所有包含的所有子模塊,如
python之塊包導入