咱們知道一個函數封裝了一個功能,軟件多是有多個函數組成的。咱們說一個函數就是一個功能,那麼把一些經常使用的函數放在一個py文件中,那麼這個文件就稱之爲模塊。模塊就是一些列經常使用功能的集合體。python
什麼是模塊:本質就是.py文件,封裝語句的最小單位。mysql
ps:人們常說的腳本是什麼?sql
若是你退出python解釋器而後從新進入,那麼你以前定義的函數或者變量都將丟失,所以咱們一般將程序寫到文件中以便永久保存下來,須要時就經過python test.py方式去執行,此時test.py被稱爲腳本script。json
因此,腳本就是一個python文件,好比你以前寫的購物車,模擬博客園登陸系統的文件等等。windows
Python語言中,模塊分爲三類。數組
第一類:內置模塊,也叫作標準庫。此類模塊就是python解釋器給你提供的,好比咱們以前見過的time模塊,os模塊。標準庫的模塊很是多(200多個,每一個模塊又有不少功能),咱們這幾天就講經常使用的十幾種,後面課程中還會陸續的講到。安全
第二類:第三方模塊,第三方庫。一些python大神寫的很是好用的模塊,必須經過pip install 指令安裝的模塊,好比BeautfulSoup, Django,等等。大概有6000多個。oracle
第三類:自定義模塊。咱們本身在項目中定義的一些模塊。app
咱們先定義一個模塊,定義一個模塊其實很簡單就是寫一個文件,裏面寫一些代碼(變量,函數)便可。此文件的名字爲tbjx.py,文件內容以下:函數
print('from the tbjx.py') name = '太白金星' def read1(): print('tbjx模塊:',name) def read2(): print('tbjx模塊') read1() def change(): global name name = 'barry'
自定義模塊:定義一個模塊其實很簡單就是寫一個文件,裏面寫一些代碼(變量,函數)便可。此文件的名字爲tbjx.py,文件內容以下:
模塊中出現的變量,for循環,if結構,函數定義。。。。稱爲模塊的成員。
自定義模塊:實際上就是定義.py文件,其中能夠包含:變量定義,可執行語句,for循環,函數定義等等,他們
統稱模塊的成員
模塊的運行方式:
1.腳本方式:python xxx.py(直接用解釋器執行) 或者在pycharm軟件run運行(右鍵運行)
2.模塊方式:被其它的模塊導入。爲導入它的模塊提供資源(變量,函數定義,類定義等)。
# b.py文件 # 可執行語句 a = 1 print(a) for x in range(10): print(x) # 函數的定義 def f(): print('hello world') f()
自定義模塊被其餘模塊導入時,其中的可執行語句會當即執行。
可是函數的定義和類的定義等是不會當即執行的。
可是咱們在實際的開發的過程當中,不是咱們import模塊就執行了。
而是在實際開發的時候用到什麼就執行什麼。
因此在模塊中,咱們通常不會寫可執行語句,而是寫變量的定義,函數定義和類定義等不會當即執行的語句。
咱們在實際的時候,不能直接可執行語句,只有變量、函數、類定義等等。被其它的模塊導入。爲導入它的模塊提供資源(變量,函數定義,類定義等)。
# test_import.py文件 import b # 輸出的結果爲: ''' 1 0 1 2 3 4 5 6 7 8 9 hello world ''' # import bb # ModuleNotFoundError: No module named 'bb'
咱們再看一下下面這個例子,咱們沒有寫可執行語句,而是變量、函數、類等的定義,不會再import時,就直接執行。
# b.py文件 # 可執行語句 a = 1 # 函數的定義 def f(): print('hello world')
import b print(b.a) b.f() print(b.f()) ''' 輸出的結果爲: 1 hello world hello world None '''
python中提供一種能夠判斷自定義模塊是屬於開發階段仍是使用階段。'name'
系統導入模塊的路徑
1.內存中:若是以前成功導入過某個模塊,直接使用已經存在的模塊
2.內置路徑中:安全路徑下:Lib
PYTHONPATH:import是尋找模塊的路徑
3.sys.path:是一個路徑的列表
若是三個都找不到,就報錯。
動態修改sys.path
os.path.dirname():獲取到某一個文件的父路徑。
一般獲取當前腳本(模塊)的相對位置,能夠獲取到每個文件。
# 查看sys.path內容 # import sys # print(sys.path) # 添加b.py所在的路徑到sys.path中 # import sys # sys.path.append(r'D:\Program Files (x86)\DjangoProjects\basic\day15\bbb') # import bb # print(bb.a) # 輸出的結果爲:get it # # 使用相對位置找到bbb文件夾中的bb # print(__file__) # 獲取當前文件的絕對路徑;D:/Program Files (x86)/DjangoProjects/basic/day15/test_imoirt.py # # 使用os模塊獲取一個路徑的父路徑 # import os # print(os.path.dirname(__file__)) # 獲取當前文件的父路徑 D:/Program Files (x86)/DjangoProjects/basic/day15 # print(os.path.dirname(__file__)+r'/bbb') # D:/Program Files (x86)/DjangoProjects/basic/day15/bbb import sys import os sys.path.append(os.path.dirname(__file__)+'/bbb')
a = 1 def main(): print(a) for x in range(3): print(x) f() # __name__屬性的使用。 if __name__ == '__main__': main() ''' 輸出的結果爲: 1 0 1 2 hello world ''' ''' __name__屬性的使用: 在腳本方式運行的時候:__name__是固定的字符串:__main__ 在模塊導入運行的時候,__name__就是被導入模塊的名字,沒有文件的後綴名.py。 在模塊方式導入時,__name__就是本模塊的名字。 經過__name__屬性,咱們就能夠決定可執行文件中的語句該不應被執行。 '''
''' 自定義模塊 ''' # age = 10 # # # def f1(): # print('hello') # # # # 測試函數,在開發階段,對本模塊中的功能進行測試。 # # 這個測試函數通常咱們是寫成main函數的形式。 # def main(): # print(age) # f1() # # # # 能夠快速生成。 # if __name__ == '__main__': # main() ''' 對於一個新的py文件或者是一個新的模塊時,咱們一上來要寫下面兩個東西. 而後根據本身的需求,去寫這個模塊對應的別的東西。例如變量的定義,函數的定義等等 ''' def main(): pass if __name__ == '__main__': main()
Python中引用模塊是按照必定的規則以及順序去尋找的,這個查詢順序爲:先從內存中已經加載的模塊進行尋找找不到再從內置模塊中尋找,內置模塊若是也沒有,最後去sys.path中路徑包含的模塊中尋找。它只會按照這個順序從這些指定的地方去尋找,若是最終都沒有找到,那麼就會報錯。
內存中已經加載的模塊->內置模塊->sys.path路徑中包含的模塊
模塊的查找順序
須要特別注意的是:咱們自定義的模塊名不該該與系統內置模塊重名。雖然每次都說,可是仍然會有人不停的犯錯
#在初始化後,python程序能夠修改sys.path,路徑放到前面的優先於標準庫被加載。 > > > import sys > > > sys.path.append('/a/b/c/d') > > > sys.path.insert(0,'/x/y/z') #排在前的目錄,優先被搜索 > > > 注意:搜索時按照sys.path中從左到右的順序查找,位於前的優先被查找,sys.path中還可能包含.zip歸檔文件和.egg文件,python會把.zip歸檔文件當成一個目錄去處理, #首先製做歸檔文件:zip module.zip foo.py bar.py import sys sys.path.append('module.zip') import foo,bar #也可使用zip中目錄結構的具體位置 sys.path.append('module.zip/lib/python') #windows下的路徑不加r開頭,會語法錯誤 sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\a') #至於.egg文件是由setuptools建立的包,這是按照第三方python庫和擴展時使用的一種常見格式,.egg文件實際上只是添加了額外元數據(如版本號,依賴項等)的.zip文件。 #須要強調的一點是:只能從.zip文件中導入.py,.pyc等文件。使用C編寫的共享庫和擴展塊沒法直接從.zip文件中加載(此時setuptools等打包系統有時能提供一種規避方法),且從.zip中加載文件不會建立.pyc或者.pyo文件,所以必定要事先建立他們,來避免加載模塊是性能降低。 接下來咱們就開始講解python經常使用的內置模塊,因爲Python經常使用的模塊很是多,咱們不可能將全部的模塊都講完, 因此只針對於工做中常常用到模塊進行講解。剩下的模塊能夠在課餘時間自學。
import 翻譯過來是一個導入的意思。
這裏必定要給同窗強調那個文件執行文件,和哪一個文件是被執行模塊。
模塊能夠包含可執行的語句和函數的定義,這些語句的目的是初始化模塊,它們只在模塊名第一次遇到導入import語句時才執行(import語句是能夠在程序中的任意位置使用的,且針對同一個模塊很import屢次,爲了防止你重複導入,python的優化手段是:第一次導入後就將模塊名加載到內存了,後續的import語句僅是對已經加載到內存中的模塊對象增長了一次引用,不會從新執行模塊內的語句),以下 import tbjx #只在第一次導入時才執行tbjx.py內代碼,此處的顯式效果是隻打印一次'from the tbjx.py',固然其餘的頂級代碼也都被執行了,只不過沒有顯示效果.
代碼示例: import tbjx import tbjx import tbjx import tbjx import tbjx 執行結果:只是打印一次: from the tbjx.py
建立一個以模塊名命名的名稱空間。
執行這個名稱空間(即導入的模塊)裏面的代碼。
經過此模塊名. 的方式引用該模塊裏面的內容(變量,函數名,類名等)。 這個名字和變量名沒什麼區別,都是‘第一類的’,且使用tbjx.名字的方式能夠訪問tbjx.py文件中定義的名字,tbjx.名字與test.py中的名字來自兩個徹底不一樣的地方。
ps:重複導入會直接引用內存中已經加載好的結果
每一個模塊都是一個獨立的名稱空間,定義在這個模塊中的函數,把這個模塊的名稱空間當作全局名稱空間,這樣咱們在編寫本身的模塊時,就不用擔憂咱們定義在本身模塊中全局變量會在被導入時,與使用者的全局變量衝突。
示例:
當前是meet.py import tbjx.py name = 'alex' print(name) print(tbjx.name) ''' from the tbjx.py alex 太白金星 ''' def read1(): print(666) tbjx.read1() ''' from the tbjx.py tbjx模塊: 太白金星 ''' name = '日天' tbjx.change() print(name) print(tbjx.name) ''' from the tbjx.py 日天 barry '''
1. 好處能夠將很長的模塊名改爲很短,方便使用.
import tbjx as t t.read1() from xxx import xxx as xxx
2. 有利於代碼的擴展和優化。
#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()
咱們之後再開發過程當中,免不了會在一個文件中,導入多個模塊,推薦寫法是一個一個導入。
import os,sys,json # 這樣寫能夠可是不推薦 推薦寫法 import os import sys import json
多行導入:易於閱讀 易於編輯 易於搜索 易於維護。
from ... import ... 的使用示例。 from tbjx import name, read1 print(name) read1() ''' 執行結果: from the tbjx.py 太白金星 tbjx模塊: 太白金星 '''
惟一的區別就是:使用from...import...則是將spam中的名字直接導入到當前的名稱空間中,因此在當前名稱空間中,直接使用名字就能夠了、無需加前綴:tbjx.
from...import...的方式有好處也有壞處
好處:使用起來方便了
壞處:容易與當前執行文件中的名字衝突
示例演示:
name = 'oldboy' from tbjx import name, read1, read2 print(name) ''' 執行結果: 太白金星 ''' ---------------------------------------- from tbjx import name, read1, read2 name = 'oldboy' print(name) ''' 執行結果: oldboy ''' ---------------------------------------- def read1(): print(666) from tbjx import name, read1, read2 read1() ''' 執行結果: tbjx模塊: 太白金星 ''' ---------------------------------------- from tbjx import name, read1, read2 def read1(): print(666) read1() ''' 執行結果: tbjx模塊: 666 '''
2. 當前位置直接使用read1和read2就行了,執行時,仍然以tbjx.py文件全局名稱空間
#測試一:導入的函數read1,執行時仍然回到tbjx.py中尋找全局變量 'alex' #test.py from tbjx import read1 name = 'alex' read1() ''' 執行結果: from the spam.py spam->read1->name = '太白金星' ''' #測試二:導入的函數read2,執行時須要調用read1(),仍然回到tbjx.py中找read1() #test.py from tbjx import read2 def read1(): print('==========') read2() ''' 執行結果: from the tbjx.py tbjx->read2 calling read tbjx->read1->tbjx 'barry' ''' 經過這種方式引用模塊也能夠對模塊進行更名。 from tbjx import read1 as read read()
from tbjx import read1,read2,name
from spam import * 把tbjx中全部的不是如下劃線(_)開頭的名字都導入到當前位置
大部分狀況下咱們的python程序不該該使用這種導入方式,由於*你不知道你導入什麼名字,頗有可能會覆蓋掉你以前已經定義的名字。並且可讀性極其的差,在交互式環境中導入時沒有問題。
可使用all來控制*(用來發布新版本),在tbjx.py中新增一行
__all__=['money','read1'] #這樣在另一個文件中用from spam import *就這能導入列表中規定的兩個名字
模塊循環/嵌套導入拋出異常的根本緣由是因爲在python中模塊被導入一次以後,就不會從新導入,只會在第一次導入時執行模塊內代碼
在咱們的項目中應該儘可能避免出現循環/嵌套導入,若是出現多個模塊都須要共享的數據,能夠將共享的數據集中存放到某一個地方在程序出現了循環/嵌套導入後的異常分析、解決方法以下(瞭解,之後儘可能避免)
示範文件內容以下
#建立一個m1.py print('正在導入m1') from m2 import y x='m1' #建立一個m2.py print('正在導入m2') from m1 import x y='m2' #建立一個run.py import m1 #測試一 執行run.py會拋出異常 正在導入m1 正在導入m2 Traceback (most recent call last): File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa練習目錄/aa.py", line 1, in <module> import m1 File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa練習目錄/m1.py", line 2, in <module> from m2 import y File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa練習目錄/m2.py", line 2, in <module> from m1 import x ImportError: cannot import name 'x' #測試一結果分析 先執行run.py--->執行import m1,開始導入m1並運行其內部代碼--->打印內容"正在導入m1" --->執行from m2 import y 開始導入m2並運行其內部代碼--->打印內容「正在導入m2」--->執行from m1 import x,因爲m1已經被導入過了,因此不會從新導入,因此直接去m1中拿x,然而x此時並無存在於m1中,因此報錯 #測試二:執行文件不等於導入文件,好比執行m1.py不等於導入了m1 直接執行m1.py拋出異常 正在導入m1 正在導入m2 正在導入m1 Traceback (most recent call last): File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa練習目錄/m1.py", line 2, in <module> from m2 import y File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa練習目錄/m2.py", line 2, in <module> from m1 import x File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa練習目錄/m1.py", line 2, in <module> from m2 import y ImportError: cannot import name 'y' #測試二分析 執行m1.py,打印「正在導入m1」,執行from m2 import y ,導入m2進而執行m2.py內部代碼--->打印"正在導入m2",執行from m1 import x,此時m1是第一次被導入,執行m1.py並不等於導入了m1,因而開始導入m1並執行其內部代碼--->打印"正在導入m1",執行from m1 import y,因爲m1已經被導入過了,因此無需繼續導入而直接問m2要y,然而y此時並無存在於m2中因此報錯 # 解決方法: 方法一:導入語句放到最後 #m1.py print('正在導入m1') x='m1' from m2 import y #m2.py print('正在導入m2') y='m2' from m1 import x 方法二:導入語句放到函數中 #m1.py print('正在導入m1') def f1(): from m2 import y print(x,y) x = 'm1' # f1() #m2.py print('正在導入m2') def f2(): from m1 import x print(x,y) y = 'm2' #run.py import m1 m1.f1()
# 導入模塊的多種方式: # import xxx導入一個模塊的全部成員 # import aaa,bbb,....一次性導入多個模塊的成員,不推薦這種寫法,分開寫比較好。因人而異。import os,sys等 # from xxx import aaa.. 從某個模塊中導入指定的成員。最大化利用。有用就導入,沒有使用咱們就不用去導入。 # from xxx import a,b,c 從某個模塊中導入多個成員。 # from xxx import * 從某個模塊彙總導入全部成員。 # import xxx 和 from xxx import * # 第一種方式在使用其中成員時,必須使用模塊名做爲前提。不容易產生命名衝突 # 第二種方式在使用其中成員時,不用使用模塊名做爲前提,直接使用成員名便可。容易產生命名衝突,在後面定義的成員生效,把前面的覆蓋了。 # 怎麼解決名稱衝突的問題 # 改用import xxx 這種方式導入 # 本身避免使用同名(alias的縮寫) # 使用別名解決衝突 from xxx import xxx as xxx # # 也能夠給模塊起別名 import my_module as m import xxx as xxx,爲了方便簡化書寫。 # from xxx import * 控制成員被導入(__all__只是適合控制這一種導入成員的方式,其他方式都是不能夠用的) # 默認狀況下,全部的成員都會被導入 # __all__是一個列表,用於表示本模塊可被外界使用的成員。元素是成員名組成的字符串。 # __all__ = [] # __all__ = [ # 'age', # 'age2' # ] # 相對導入:相對導入時導入的是同項目下的模塊。 # 只有一種的導入的方式 # from xxx import xxx # import os # import sys # # 把項目所在的父路徑加到sys.path中,python的解釋器中。os是操做系統相關的路徑。 # sys.path.append(os.path.dirname(__file__)) # from xx.y import yy # print(yy.age2) # # 使用相對位置找到bbb文件夾中的bb # print(__file__) # 當前文件的絕對路徑;D:/Program Files (x86)/DjangoProjects/basic/day15/test_imoirt.py # # 使用os模塊獲取一個路徑的父路徑 # import os # print(os.path.dirname(__file__)) # 獲取當前文件的父路徑 D:/Program Files (x86)/DjangoProjects/basic/day15 # print(os.path.dirname(__file__)+r'/bbb') # D:/Program Files (x86)/DjangoProjects/basic/day15/bbb