標籤:python基礎 模組與包
1、模組匯入方法
常見的情境:
一個模組就是一個包含了python定義和聲明的檔案,檔案名稱就是模組名字加上.py的尾碼,匯入模組可以實現功能的重複利用
import載入的模組分為四個通用類別:
1 使用python編寫的代碼(.py檔案)
2 已被編譯為共用庫或DLL的C或C++擴充
3 包好一組模組的包
4 使用C編寫並連結到python解譯器的內建模組
a. import語句
python 內建了很多模組,比如os、sys、time等,也可以是自訂模組、模組包、C擴充等,使用import無法區分匯入的模組類型
import 模組名
例如:匯入spam.py
import spam(不含.py)
匯入多個模組:
import os,time,sys
模組可以包含可執行檔語句和函數的定義,這些語句的目的是初始化模組,它們只在模組名第一次遇到匯入import語句時才執行(import語句是可以在程式中的任意位置使用的,且針對同一個模組import很多次,為了防止你重複匯入,python的最佳化手段是:第一次匯入後就將模組名載入到記憶體了,後續的import語句僅是對已經載入大記憶體中的模組對象增加了一次引用,不會重新執行模組內的語句)
每個模組都是一個獨立的名稱空間,定義在這個模組中的函數,把這個模組的名稱空間當做全域名稱空間,這樣我們在編寫自己的模組時,就不用擔心我們定義在自己模組中全域變數會在被匯入時,與使用者的全域變數衝突
匯入模組幹了哪些事:
1 執行源檔案
2 以一個源檔案的全域名稱空間
3 在當前位置拿到一個模組名,指向2建立的名稱空間
#測試一:money與spam.money不衝突#test.pyimport spammoney=10print(spam.money)輸出:from the spam.py1000 #測試二:read1與spam.read1不衝突#test.pyimport spamdef read1(): print(‘========‘)spam.read1()輸出:from the spam.pyspam->read1->money1000#測試三:執行spam.change()操作的全域變數money仍然是spam中的#test.pyimport spammoney=1spam.change()print(money)輸出:from the spam.py1
模組別名功能
練習:
有兩鐘sql模組mysql和oracle,根據使用者的輸入,選擇不同的sql功能
#mysql.pydef sqlparse(): print(‘from mysql sqlparse‘) #oracle.pydef sqlparse(): print(‘from oracle sqlparse‘) #test.pydb_type=input(‘>>: ‘)if db_type == ‘mysql‘: import mysql as dbelif db_type == ‘oracle‘: import oracle as db db.sqlparse()
為已經匯入的模組起別名的方式對編寫可擴充的代碼很有用,假設有兩個模組xmlreader.py和csvreader.py,它們都定義了函數read_data(filename):用來從檔案中讀取一些資料,但採用不同的輸入格式。可以編寫代碼來選擇性地挑選讀模數塊
if file_format == ‘xml‘: import xmlreader asreaderelif file_format == ‘csv‘: import csvreader asreaderdata=reader.read_date(filename)
b. from…import語句
from 模組名 import 模組名中的方法
例如:from spamimport money,read1,read2,change
如果模組中的方法太多,可以使用:
from spam import * (不推薦使用,容易與執行檔案的命名空間衝突)
__all__=[‘money‘,‘x‘] #對from spam import * 有用,之後匯入money、x方法
_money=1000 #對from spam import * 有用,不會匯入這個方法
對比import spam,會將源檔案的名稱空間‘spam‘帶到當前名稱空間中,使用時必須是spam.名字的方式,而from 語句相當於import,也會建立新的名稱空間,但是將spam中的名字直接匯入到當前的名稱空間中,在當前名稱空間中,直接使用名字就可以了
#spam.pyprint(‘from the spam.py‘)money=0def read1(): print(‘spam->read1->money‘,money)def read2(): print(‘spam->read2 calling read‘) read1()def change(): global money money=0 # 執行檔案from spam import money,read1,read2,changemoney=0print(money)print(read1)輸出:from the spam.py #首先執行spam.py0 #仍然是當前執行檔案的命名空間中的money<function read1 at 0x00000000026DE950>
優點:使用源檔案內的名字時無需加首碼,使用方便
缺點:容易與當前檔案的名稱空間內的名字混淆
c. 模組搜尋路徑
模組只在第一次匯入時才會執行,之後的匯入都是直接引用記憶體已經存在的結果
import sys
print(‘spam‘ in sys.modules) #存放的是已經載入到內的模組
注意:自訂的模組名一定不要與python內建的模組名重名
模組的尋找順序是:記憶體中已經載入的模組->內建模組->sys.path路徑中包含的模組
import timeimport importlibimport spam #匯入模組會把硬碟中的模組內容載入到記憶體中time.sleep(20)import spam #再次匯入會直接從記憶體中尋找,忽略硬碟中模組內容print(spam.money)importlib.reload(spam) #會重新載入模組(只在測試環境使用)print(spam.money)
import sys
print(sys.path) #模組的搜尋路徑
sys.path從以下位置初始化
1 執行檔案所在的目前的目錄
2 PTYHONPATH(包含一系列目錄名,與shell變數PATH文法一樣)
3 依賴安裝時預設指定的
加入模組路徑:
import sysprint(sys.path)sys.path.insert(0,r‘要添加的模組路徑‘) #插入模組路徑sys.path.append(r‘要添加的模組路徑‘) #追加模組路徑
d. 區分python檔案的兩種用途
檔案當做指令碼(執行檔案)運行時__name__等於__main__
檔案當做模組被載入運行時__name__等於模組名
# m1.pyimport os,sysx=1def func1(): print(‘from m1‘)def func2(): print(‘from m2‘)def func3(): print(‘from m3‘)# print(__name__)#檔案當做指令碼運行時__name__等於__main__#檔案當做模組被載入運行時__name__等於模組名if __name__ == ‘__main__‘: #當做指令碼使用時才執行 func1() func2() func3() # run.py import m1 #匯入m1模組m1.func3()
e. 包
python3中建立檔案夾會自動建立__init__.py
python2中建立包需要手動建立__init__.py
1. 無論是import形式還是from...import形式,凡是在匯入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的匯入文法
2. 包是目錄級的(檔案夾級),檔案夾是用來組成py檔案(包的本質就是一個包含__init__.py檔案的目錄)
3. import匯入檔案時,產生名稱空間中的名字來源於檔案,import 包,產生的名稱空間的名字同樣來源於檔案,即包下的__init__.py,匯入包本質就是在匯入該檔案
強調:
1. 在python3中,即使包下沒有__init__.py檔案,import 包仍然不會報錯,而在python2中,包下一定要有該檔案,否則import 包報錯
2. 建立包的目的不是為了運行,而是被匯入使用,記住,包只是模組的一種形式而已,包即模組
3.凡是在匯入時帶點的,點的左邊都必須是一個包
本文出自 “lyndon” 部落格,請務必保留此出處http://lyndon.blog.51cto.com/11474010/1953171
python基礎---模組與包