1、什麼是模塊數據庫
模塊就是一系列功能的集合體,一個模塊就是一個包含了Python定義和聲明的文件,文件名就是模塊名字加上.py的後綴。app
模塊有三種來源:spa
一、內置的模塊3d
二、第三方的模塊日誌
三、自定義模塊code
模塊的四種通用類別:blog
一、使用Python編寫的代碼(.py文件)內存
二、已被編譯爲共享庫或DLL的C或C++擴展開發
三、把一系列模塊組織到一塊兒的文件夾(注:文件夾下有一個__init__.py文件,該文件夾稱之爲包)字符串
四、使用C編寫並連接到Python解釋器的內置模塊
2、爲什麼要用模塊
一、使用內置的或者第三方模塊的好處是:拿來就可使用,能夠極大提高開發效率
二、使用自定義模塊的好處是:能夠減小代碼冗餘(抽取咱們本身程序中要公用的一些功能定義成模塊,而後程序的各部分組件都去模塊中調用共享的功能)
3、模塊的使用
前提:必定要區分開誰是執行文件,誰是被導入模塊
一、import導入模塊
在Pycharm中右鍵新建一個文件,文件名是spam.py,模塊名是spam,再新建一個文件叫run.py,在run.py中
import spam
首次導入一個模塊,會發生如下事情:
1)會產生一個模塊的名稱空間
2)執行文件spam.py,將執行過程當中產生的名字都放到模塊的名稱空間中
3)在當前執行文件的名稱空間中拿到一個模塊名,該名字指向模塊的名稱空間
以後的導入,都是直接引用第一次導入的成果,不會從新執行文件
在spam.py文件中添加代碼
money = 1000
def read1(): print('spam模塊:',money) def read2(): print('spam模塊') read1() def change(): global money money = 0
在執行文件中訪問模塊名稱空間中名字的語法:模塊名.名字,即在run.py中
import spam print(spam.money) # 1000
print(spam.read1) # <function read1 at 0x000001CE16209B70>
print(spam.read2) # <function read2 at 0x000001CE16209A60>
print(spam.change) # <function change at 0x000001CE16209C80>
spam.read1() # spam模塊: 1000
def read1(): print('run.py --> read1') read1() # run.py --> read1
spam.read2() # spam模塊
# spam模塊: 1000
money = 9999 spam.change() print(spam.money) # 0
print(money) # 9999
總結 import 導入模塊:在使用時必須加上模塊名做爲前綴
優勢:指名道姓的向某一個名稱空間拿取名字,不會與當前名稱空間中的名字衝突
缺點:但凡應用模塊中的名字都須要加前綴,不夠簡潔
還能夠一行導入多個模塊,但不推薦使用
import spam, os, time
能夠爲模塊起別名(注意:模塊名應全爲小寫)
import spam as sm print(sm.money) print(sm.read1)
二、from...import...導入模塊
首次導入模塊發生的三件事:
1)建立一個模塊的名稱空間
2)執行文件spam.py,將執行過程當中產生的名字都放到模塊的名稱空間中
3)在當前執行文件中直接拿到一個名字,該名字就是執行模塊中相對應的名字
刪除上面的兩個文件,從新建一個spam.py,添加代碼
money = 1000
def read1(): print('spam模塊:',money) def read2(): print('spam模塊') read1() def change(): global money money = 0
再新建一個run.py,在run.py中
from spam import money print(money) # 1000
from spam import money money = 200
print(money) # 與當前名稱空間中的名字衝突, 結果爲200
總結from...import...導入模塊
優勢:使用時,無需再加前綴,更簡潔
缺點::容易與當前名稱空間中的名字衝突
如今將run.py裏的代碼改爲
from spam import money, read1 money = 200
# 這裏執行read1裏面的money仍是1000,由於在定義階段就已經固定死了,與調用位置無關
read1() # spam模塊: 1000
print(money) # 200
還能夠導入所有模塊,但不推薦使用
# 星號表明從被導入模塊中拿到全部名字
from spam import *
有一個 __all__ 的功能,將指定的模塊名以字符串的形式存放,若是再使用星號導入模塊,這時導入的就是 __all__裏面的內容,而不是導入所有的模塊,例如:
在spam.py中定義 __all__
__all__ = ['money', 'read1'] money = 1000
def read1(): print('spam模塊:',money) def read2(): print('spam模塊') read1() def change(): global money money = 0
在run.py中用星號導入
from spam import * read1() # spam模塊: 1000
read2() # 報錯, 由於 __all__沒有包含read2模塊
能夠爲模塊起別名
from spam import read1 as r1 r1()
4、Python文件的兩種執行方式
一、直接運行
二、做爲模塊導入
# 在m1.py中
def f1(): print('f1') print(__name__) # 執行後是 __main__
# 在run.py中
import m1 # 執行後是 m1
即:當作腳本運行,__name__ 等於'__main__',當作模塊導入,__name__等於模塊名
因此這個條件是:if __name__ == '__main__': ,用來控制.py文件在不一樣的應用場景下執行不一樣的邏輯
# 在m1.py中
def f1(): print('f1') if __name__ == '__main__': f1() # 在run.py中
import m1
5、模塊的搜索路徑
一、模塊搜索路徑的優先級
1)內存中已經加載過的
2)內置模塊
3)sys.path(第一個值是當前執行文件所在的文件夾)
模塊搜索路徑優先從內存中已加載過的開始查找,例如我新建一個m1.py和一個run.py,在run.py中導入模塊m1
# m1.py
def f1(): print('from f1') # run.py
import time import m1 time.sleep(10) # 程序睡眠10秒的過程當中刪除m1.py
import m1 m1.f1() # 這裏還能夠執行
刪除m1.py文件後再導入執行不會報錯,由於在刪除的過程當中程序沒有結束,再次導入是優先從內存中查找,找到了直接運行,但若是再次運行就會報錯,由於內存已經回收,找不到m1模塊了
注意:不該該將本身的模塊名命名成與內置模塊或第三方模塊的名字相同
二、添加sys.path
新建m1.py和run.py,將m1.py放在dir1文件夾下,讓dir1文件夾和run.py在同一級目錄
# m1.py def f1(): print('from f1')
f1() # run.py import m1 # 這時候是找不到的,可是若是添加sys.path,將run.py改爲以下
# run.py import sys sys.path.append('E://Test//dir1') # 將m1所在的文件夾路徑添加到sys.path import m1
三、from...import...
仍是上面的狀況,能夠在run.py裏面經過from...import...導入
from dir1 import m1
這是在sys.path中找到的,可是我沒有添加sys.path,爲何也能找到呢?
由於sys.path的第一個值是當前執行文件所在的文件夾,也就是Test文件夾(個人run.py和dir1的上一層是Test文件夾),因此說是以當前執行文件的sys.path爲準,能夠找到dir1,進而找到m1
基於上面的目錄,我在dir1下新建一個文件夾叫dir2,在dir2中新建一個文件叫m2.py,如今的路徑關係是:Test下面有一個run.py和dir1,dir1下有一個m1.py和dir2,dir2下有一個m2.py
m2中添加代碼
def f2(): print('from f2')
f2()
能夠經過from...import...導入
from dir1.dir2 import m2
第一種特殊狀況:模塊的絕對導入
刪除上面的全部文件,新建run.py和dir1文件夾,在dir1下新建m1.py和m2.py
# m1.py
def f1(): print('from f1') # m2.py
def f2(): print('from f2')
run想訪問m1,由於不在同一級目錄,因此要經過上面講到的兩種方法(添加sys.path或from...import導入)來訪問(我用後者)
# run.py
from dir1 import m1
如今我執行run.py,能夠經過run訪問到m1
如今m1想訪問m2,只須要在m1中導入m2便可
# m1.py
import m2 def f1(): print('from f1') m2.f2()
可是如今,我再執行run.py,可否經過run訪問到m1再訪問到m2呢?
不行!由於sys.path是以當前執行文件爲準的,那麼sys.path的第一個值就是 E://Test//,在m1裏面導入m2的時候,去sys.path中沒法找到m2,因此會報錯
強調:全部被導入的模塊參照的環境變量sys.path都是以執行文件爲準的
那麼怎麼解決呢
# m1.py
from dir1 import m2 def f1(): print('from f1') m2.f2() # m2.py
def f2(): print('from f2') # run.py
from dir1 import m1 m1.f1()
注意:不要理解成sys.path是以執行文件所在的文件夾爲準,由於sys.path有不少個值,而執行文件所在的文件夾僅僅只是sys.path中的一個值,這個執行文件所在的文件夾找不到後面還有不少值能夠找
上面這種狀況是以執行文件的sys.path做爲參考點開始導入,稱之爲模塊的絕對導入
優勢:在執行文件與被導入的模塊中均可以使用
缺點:全部導入都是以sys.path爲參考點,導入麻煩
第二種特殊狀況:模塊的相對導入
參照當前所在文件的文件夾爲起始開始查找,稱之爲模塊的相對導入
符號:.(一個點)表明當前所在文件的文件夾,..(兩個點)表明上一級文件夾,...(三個點)表明上一級的上一級文件夾
優勢:導入更加簡單
缺點:只能在被導入的模塊中使用,不能在執行文件中用
如今在Test下新建一個dir0,dir0下新建一個dir1和run.py,dir1下新建m1.py和m2.py
# run.py
from dir0.dir1 import m1 # 用的仍是絕對導入
m1.f1() # m1.py
from . import m2 # 用的是相對導入
def f1(): print('from f1') m2.f2() # m2.py
def f2(): print('from f2')
6、軟件開發的目錄規範
以 「ATM+購物車」 舉例
ATM + 購物車 bin: 整個程序的執行文件,入口(調用核心邏輯的一些功能) - start.py conf: 配置文件(程序組件共用的變量) - settings.py lib: 庫(自定義的模塊, 程序組件共用的功能) - common.py core: 核心邏輯(與業務相關的邏輯, 購物車的登陸註冊轉帳取款等) - src.py log: 日誌(程序運行產生的關鍵信息記錄) - transaction.log db: 數據(數據庫相關的文件) Readme: 讀我(軟件的介紹, 說明書)
調用業務相關的邏輯應該經過start.py去調取src模塊,因此要添加環境變量,而後在start.py中添加代碼
# run.py
import sys sys.path.append(r'E:\Python\ATM\core') import src src.run()
雖然添加core可以讓start.py調取到src模塊,但可不能這麼作。由於之後別人做爲軟件的使用者,下載了這個軟件而後使用,但這裏添加的環境變量是開發者本身機器上的文件路徑,別人使用時和我確定不是同樣的文件路徑,因此沒法使用。這時須要讓使用者不管在哪一個路徑下都能使用這個軟件,因此要添加一個通用的環境變量,具體作法是添加整個項目的根文件夾。可是這裏可不能又寫我硬盤上的文件路徑,而是讓程序本身獲取整個項目的根文件夾。
# run.py
print(__file__) # 運行
E:/Python/ATM/bin/start.py
__file__能夠獲取當前執行文件的絕對路徑,不一樣的機器能夠獲取不一樣的絕對路徑。如今須要獲取執行文件所在文件夾的父級文件夾,因此能夠基於__file__來獲取
os模塊有個功能能夠獲取當前執行文件所在的文件夾的路徑
# run.py
import os print(os.path.dirname(__file__)) # 運行
E:/Python/ATM/bin
那麼基於上面獲取父級文件夾就是再使用一個os.path.dirname
# run.py
import os print(os.path.dirname(os.path.dirname(__file__))) # 運行
E:/Python/ATM
這時便獲取到了執行文件所在文件夾的父級文件夾,而後添加到環境變量,之後不管這個軟件在哪臺機器上運行,均可以獲得精準的目錄
# run.py
import os import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import src src.run()
有一個標準的寫法,是將if __name__ == '__main__': 添加進去
# run.py
import os import sys BASE_DIR = os.path.dirname(os.path.dirname(__file__)) sys.path.append(BASE_DIR) from core import src if __name__ == '__main__': src.run()